My dear reader, how are you? السلام عليكم
I am not young enough to know everything — Oscar Wilde
This is the second part of DjangoBlog tutorial series. This post extends our basic application with a post sharing via email feature and a blog commenting system.
Few useful links to practically follow the project:
- DjangoBlog GitHub repository — DirectMe
- All other tutorials on Django-Blog — DirectMe
- Set your GitHub repo to DjangoBlog Part 1 using the following command:
git fetch origin 4dff851fa16284572b1bbc014b762b41830ec5dc
Sharing Blog posts via email
Django supports two types of forms, i.e.,
- Form: Standard forms
- ModelForm: Forms tied to the model instances
For post sharing we build define a standard form as shown below:
# create blog/forms.py and add the following program into it 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)
We will now use forms in views as shown below:
# open blog/views.py and add the following program from .forms import EmailPostForm def post_share(request, post_id): post = get_object_or_404(Post, id=post_id, status='published') if request.method == 'POST': form = EmailPostForm(request.POST) if form.is_valid(): cd = form.cleaned_data else: form = EmailPostForm() return render(request, 'blog/post/share.html', {'post': post, 'form': form})
In order to send emails via Django, we first need to configure SMTP server by adding the following lines in config/settings.py
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_HOST = 'smtp.gmail.com' EMAIL_HOST_USER = '[email protected]' EMAIL_HOST_PASSWORD = 'your_password' EMAIL_PORT = 587 EMAIL_USE_TLS = True
We now add the emailing functionality to our views by extending the post_share as shown below:
# open views.py and add the program shown in bold def post_share(request, post_id): ... ... cd = form.cleaned_data post_url = request.build_absolute_uri( post.get_absolute_url()) subject = '{} ({}) recommends you reading "{}"'.format(cd['name'], cd['email'], post.title) message = 'Read "{}" at {}\n\n{}\'s comments: {}'.format(post.title, post_url, 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})
We now need to add a route to post share
# open blog/urls.py and add the following path urlpatterns = [ ... path('<int:post_id>/share/', views.post_share, name='post_share'), ]
Finally, we need to add templates for sharing the posts as shown below:
# Create blog/templates/blog/post/share.html and add the following program {% 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 {{ form.cleaned_data.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 %} # open blog/templates/blog/post/detail.html and add the following in bold {% extends "blog/base.html" %} ... ... {{ post.body|linebreaks }} <p> <a href="{% url "blog:post_share" post.id %}"> Share via email </a> </p> {% endblock %}
A USER Commenting FEATURE on BLOG POSTS
We first will add a model for comment as shown below:
# Open blog/moodel.py and add the following class Comment(models.Model): post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments') name = models.CharField(max_length=80) email = models.EmailField() body = models.TextField() created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) active = models.BooleanField(default=True) class Meta: ordering = ('created',) def __str__(self): return 'Comment by {} on {}'.format(self.name, self.post) # add the migrations (blogenv)Django-Blog-Application/Django-Blog$ python3 manage.py makemigrations (blogenv)Django-Blog-Application/Django-Blog$ python3 manage.py migrate
Let us add a Comment listing on the admin panel as shown below:
# open blog/admin.py and add a customized admin page listing for Comment from django.contrib import admin from .models import Post, Comment @admin.register(Comment) class CommentAdmin(admin.ModelAdmin): list_display = ('name', 'email', 'post', 'created', 'active') list_filter = ('active', 'created', 'updated') search_fields = ('name', 'email', 'body')
We now create a form for Comment. This form should use the entities of Comment model so we can use ModelForm instead of the standard form as shown below:
# open blog/forms.py and add the following program from .models import Comment class CommentForm(forms.ModelForm): class Meta: model = Comment fields = ('name', 'email', 'body')
Let us add this functionality in detail.py template as shown below:
# open blog/templates/blog/post/detail.html and extend with the following program {% with comments.count as total_comments %} <h2> {{ total_comments }} comment{{ total_comments|pluralize }} </h2> {% endwith %} {% for comment in comments %} <div class="comment"> <p class="info"> Comment {{ forloop.counter }} by {{ comment.name }} {{ comment.created }} </p> {{ comment.body|linebreaks }} </div> {% empty %} <p>There are no comments yet.</p> {% endfor %} {% if new_comment %} <h2>Your comment has been added.</h2> {% else %} <h2>Add a new comment</h2> <form action="." method="post"> {{ comment_form.as_p }} {% csrf_token %} <p><input type="submit" value="Add comment"></p> </form> {% endif %}
If you run the development server at this point in time you should be able to see the added functionalities at http://127.0.0.1:8000/blog/
I hope you find this tutorial useful. If you find any errors or feel any need for improvement, let me know in your comments below.
Signing off for today. Stay tuned and I will see you next week! Happy learning.