Creating the interface for the share feature

We will implement the form feature, which, in essence, is another view in our blog application. To do this, perform the following steps:

  1. First, create a new Python script inside the blog folder in the forms.py directory, as follows:
from django import forms


class EmailPostForm(forms.Form):
name = forms.CharField(max_length=25)
email = forms.EmailField()
to = forms.EmailField()
comments = forms.CharField(required=False, widget=forms.Textarea)

You can see that this file resembles a model declaration in Django; while the basic implementation is similar, Django forms are organized in the forms.py directory, separate from models. Here, we can see that, once again, Django offers an easy and straightforward API that implements the backend logic for complex tasks. In this case, this is for the input field for emails, as well as for specifying widgets for character fields (for the comments).

  1. Next, we will implement a view for this form by adding the following code to the blog/views.py file:
from .forms import EmailPostForm
from django.core.mail import send_mail


def post_share(request, post_id):
post = get_object_or_404(Post, id=post_id, status='published')
sent = False

if request.method == 'POST':
form = EmailPostForm(request.POST)

if form.is_valid():
cd = form.cleaned_data
post_url = request.build_absolute_uri(post.get_absolute_url())
subject = f'{cd["name"]} ({cd["email"]}) sent you
a blog post: "{post.title}"'
message = f'Read "{post.title}" at {post_url} '
message += f'Comments from {cd["name"]}:
{cd["comments"]}'
send_mail(subject, message, '[email protected]',
[cd['to']])
sent = True
else:
form = EmailPostForm()

return render(
request,
'blog/post_share.html',
{'post': post, 'form': form, 'sent': sent}
)

Here, our new view, post_share(), takes in an ID number for a specific blog post (in addition to a request). Then, we query our database to obtain this post and check to see if it is indeed a published one.

Next, there are two possible scenarios/cases that we need to handle in this view:

  • If the request that's passed to the view is a POST request (checked by the first if statement), then that indicates to us that a reader has submitted their data via the implemented form. In this case, we will retrieve the submitted data by wrapping the EmailPostForm class around the POST request and accessing its cleaned_data attribute.
    After this, we need to write the code that actually sends out an email to the intended receiver. From the submitted data, we obtain the appropriate information, such as sender name (cd['name']) and email (cd['email']), what specific post to share (post.title and post_url), as well as any potential comments (cd['comments']).
    Finally, we pass all of this information to the send_mail() method from Django, which will facilitate the actual process of sending the email. Note that I'm specifying the sender of the email to be [email protected], which will not be the case for you. Don't worry about this for now, as we will come back to this point in the next section.
  • If this view did not receive a POST request, we simply initialize a new EmailPostForm object to be displayed on the appropriate page.
  1. As always, we will pass the processed data, along with the template that corresponds to this view, to a file. In this case, we are talking about the blog/post_share.html file, which hasn't been created yet. Simply use PyCharm's Intention feature to create and open the template in the editor. Enter the following code into the template:
{% extends "blog/base.html" %}
{% block title %}Share a post{% endblock %}
{% block content %}
{% if sent %}
<h1>E-mail successfully sent</h1>
<p>
"{{ post.title }}" was successfully sent to {{ cd.to
}}.
</p>
{% else %}
<h1>Share "{{ post.title }}" by e-mail</h1>
<form action="." method="post">
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value="Send e-mail">
</form>
{% endif %}
{% endblock %}

In this template, we are also handling the two cases that correspond to the logic we discussed in the view. The distinction between these two cases is stored in the variable that's sent (initialized in the post_share view), which indicates whether an email has been successfully sent from a submitted form or whether a reader is simply requesting a new form.

In the former case, we simply display an appropriate message indicating that an email has been sent. In the latter case, we render the form variable as a paragraph HTML element using the as_p method inside a <form></form> tag that contains a POST method.

Additionally, the {% csrf_token %} tag is a way to generate a token that counters CSRF (short for cross-site request forgery) attacks. Keeping things at a high level, we don't need to understand this point in depth, but it is important to remember that this tag is required in a Django application in any given form element.

  1. Next, we need to add the link we just implemented in each detail view. In the post_detail.html template, add the following code, just before the {% endblock %} tag at the end of the file:
<p>
<a href="{% url "blog:post_share" post.id %}">
Share this post
</a>
</p>
  1. Finally, we specify another item in our list of URL patterns, redirecting any applicable request to the post_share view in the blog/urls.py file:
urlpatterns = [
...
url(r'^(?P<post_id>d+)/share/$', views.post_share,
name='post_share'), # share view
]

With that, the interface for our share feature is complete.

  1. Go ahead and launch the server and go to any individual blog post. Here, you will see the share button at the end of the post, as highlighted in the following screenshot:

The share button in the blog application
  1. Next, click on the URL. You will be taken to the page associated with the share feature. Since we are filling out a new form for the first time (as opposed to submitting a form), we will see the following page:

A form element rendered in Django

This is when we can fully appreciate the powerful as_p method that we used earlier—our form element is automatically rendered with the individual questions (attributes of the EmailPostForm class) with the appropriate response sections.

Furthermore, since name, email, and to are required questions, you won't be able to submit a form if any of those questions are not answered. Similarly, email and to are email fields, so if their responses are not in the correct email format (for example, not containing an @ character), then those responses will not be accepted either.

Now, say you have filled out this form with responses of the correct format and click the Send Email button to submit the form. At this point, we will receive a ConnectionRefusedError exception, which has been raised by Django. This is because we haven't configured the backend of our emailing protocols yet. We will discuss this in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset