How To Create A Comment Section For Django Blog/Website in Just 5 Steps using django-comments-xtd ?

This blog post is sponsored by Webisoft.com, a django dev shop in Canada.

Are you working on your Django website and want to learn how to add a comment section to your website/blog in just 5 steps? If yes, then this article is for you.

Note: If you want to save it for later then download the pdf.

At the end of this tutorial you will be able to:

  1. Add a comment section on your blog.
  2. Add replies on comments up to 2 levels. ( You can add more levels according to your requirement. It is super easy.)

Features.

  1. No need for authentication for adding comments.
  2. Only email and name are required for adding comments.
  3. You can also follow up on comments.

Want to see the live demo before starting? laugh 

Note: someone ( a bot) is posting irrelevant spam comments on this blog post so thats why I have hidden the comment section for sometime. So if you want to test th comment functionality you can test on some other article of my website.

You can test the functionality by adding some comments on this blog post in the comment section. But please don't spam xD. Comments should be relevant to the post.

Let's move toward coding.

First, we are creating a simple functionality of listing blogs and showing blog detail. So you can escape this section if you have already added the code for the blog list and blog detail.

# YouApp/models.py

from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.urls import reverse
 
 
class BlogPost(models.Model):
    title = models.CharField(
        _("Blog Title"), max_length=250,
        null=False, blank=False
    )
    slug = models.SlugField(unique=True)
    body = models.TextField()
    date_published = models.DateTimeField(null=True, blank=True,
                                          default=timezone.now
                                          )
 
    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("blog:blog_detail", kwargs={"slug": self.slug})

Now add the code for blog listing and blog detail. Here I am using class base views, you can use either class base or function base.

# YourApp/views.py

from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
 
from .models import BlogPost
 
 
class BlogListView(ListView):
 
    queryset = BlogPost.objects.all()
    context_object_name = 'blog_posts'
    template_name = 'blog/blog_list.html'
 
 
class BlogDetailView(DetailView):
 
    model = BlogPost
    context_object_name = 'blog_detail'
    template_name = 'blog/blog_detail.html'

 Then add the URLs for the above views in urls.py.

# YourApp/urls.py

from django.urls import path
 
from .views import (
    BlogListView, BlogDetailView
)
 
app_name = "blog"
 
urlpatterns = [
    path('', BlogListView.as_view(), name="blog"),
    path('<str:slug>/', BlogDetailView.as_view(), name="blog_detail"),
]

 Now add a template for blog list.

<!-- templates/blog/blog_list.html -->

{% extends 'base.html' %}
 
{% block content %}
 
<!-- nav bar -->
<nav aria-label="breadcrumb">
    <ol class="breadcrumb">
      <li class="breadcrumb-item active" aria-current="page">All Blogs</li>
    </ol>
</nav>
 
<!-- Blog list -->
<div class="container">
    {% for blog in blog_posts  %}
        <div class="card text-white bg-dark mb-3" style="max-width: 18rem;">
            <div class="card-header">{{ blog.date_published }}</div>
            <div class="card-body">
                <h5 class="card-title">
                    <a href="{% url 'blog:blog_detail' blog.slug %}">{{ blog.title }}</a>
                </h5>
            <p class="card-text">{{ blog.body|striptags|truncatewords:20 }}......</p>
            </div>
        </div>
    {% endfor %}
</div>
   
{% endblock content %}

Comments Configuration.

Now, let's move toward the comments integration part. For comments integration, I am using a Django package django_comments_xtd. First, install the package by running this command.

pip install django-comments-xtd

Edit the settings module, mainproject/settings.py, and make the following changes:

1. Add 'django.contrib.sites', 'django_comments_xtd' and 'django_comments' in INSTALLED_APPS

#settings.py

INSTALLED_APPS = [
    '.....'
    'django.contrib.sites',
    '....'

    # django_comments_xtd and django_comments order should be same
    'django_comments_xtd',
    'django_comments',  
]

2. Define SITE_ID (Visit the admin site and be sure that the domain field of the Site instance points to the correct domain (localhost:8000 when running the default development server), as it will be used to create comment verification URLs, follow-up cancellations, etc.)

#settings.py

SITE_ID = 1

3. Set COMMENTS_APP = 'django_comments_xtd'

#settings.py

COMMENTS_APP = 'django_comments_xtd'

4. Set the COMMENTS_XTD_MAX_THREAD_LEVEL  to N, being N the maximum level of threading up to which comments will be nested in your project.

# settings.py

# Set the COMMENTS_XTD_MAX_THREAD_LEVEL to N, being N the maximum 
# level of threading up to which comments will be nested in your project.
# 0: No nested comments:
#  Comment (level 0)

# 1: Nested up to level one:
#  Comment (level 0)
#   |-- Comment (level 1)

# 2: Nested up to level two:
#  Comment (level 0)
#   |-- Comment (level 1)
#        |-- Comment (level 2)

COMMENTS_XTD_MAX_THREAD_LEVEL = 2

Then add the following.

# settings.py

COMMENTS_XTD_CONFIRM_EMAIL = False

# Either enable sending mail messages to the console:
# EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

# or smpt EmailBackend
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

# Or set up the EMAIL_* settings so that Django can send emails:
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = "587"
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'Your email'
EMAIL_HOST_PASSWORD = 'Your email password'
DEFAULT_FROM_EMAIL = "Helpdesk <helpdesk@yourdomain>"

5. Now edit the URLs module of the project, main_project/urls.py.

from django.urls import path, include

urlpatterns = [
    ...
    path('comments/', include('django_comments_xtd.urls')),
    ...
]

Now run python manage.py migrate. And add blog_detail.html file

Stop here!.   This template is important. because here we will change the blog_detail template to:

1. Display the total number of comments made on the blog post. (Done by this tag get_comment_count )

2. List the already posted comments. (Done by this tag {% render_xtdcomment_tree for object %} )

3. Show the comment form, so that comments can be sent. (Done by this tag {% render_comment_form for object %} )

<!-- templates/blog_detail.html -->

{% extends 'base.html' %}
 
{% load static %}
<!-- for comments -->
{% load comments %}
{% load comments_xtd %}
 
{% block content %}
 
<!-- nav bar -->
<nav aria-label="breadcrumb">
    <ol class="breadcrumb">
        <li class="breadcrumb-item"><a href="{% url 'blog:blog' %}">All Blogs</a></li>
        <li class="breadcrumb-item active" aria-current="page">{{ blog_detail.title }}</li>
    </ol>
</nav>
 
<div class="container">
        <div class="card text-white bg-dark mb-3" style="max-width: 50rem;">
            <div class="card-header">{{ blog_detail.date_published }}</div>
            <div class="card-body">
                <h5 class="card-title">
                    {{ blog_detail.title }}
                </h5>
            <p class="card-text">{{ blog_detail.body }}</p>
            </div>
        </div>
</div>
 
<!-- For Comments - This code will show the NUMBER OF COMMENTS POSTED.  -->
{% get_comment_count for object as comment_count %}
    <div class="py-4 text-center">
   
    <!-- Comment count -->
    &nbsp;&sdot;&nbsp;
    {{ comment_count }} comment{{ comment_count|pluralize }}
    ha{{ comment_count|pluralize:"s,ve"}} been posted.
    </div>
 
    <!-- Posted comment list - This code will show the POSTED COMMENTS -->
    {% if comment_count %}
        <ul class="media-list shadow p-3 mb-5 bg-white rounded container">
        {% render_xtdcomment_tree for object %}
        </ul>
    {% endif %}
 
    <!-- Post your comment - This code will show the FORM TO POST COMMENTS -->
    <div class="comment mt-3 shadow p-3 mb-5 bg-white rounded container">
        <h4 class="text-center mb-4">Your comment</h4>
        <div class="card pt-4">
            {% render_comment_form for object %}
        </div>
    </div>
   
 
{% endblock content %}

Follow Up comments.

1. When someone comments on your blog post then you will receive a comment email.

2. When some user comments and follows the follow-up comment by pressing the follow-up checkbox. Then when another user replies to that comment, the user receives an email about the replied comment.

Note: Since Google has removed the allow less secure app access. So while using your email and password in settings.py you will get the following error.

smtplib.SMTPAuthenticationError: (535, b'5.7.8 Username and Password not accepted. Learn more at\n5.7.8  https://support.google.com/mail/?p=BadCredentials h5-wmq.22 - gsmtp')

Solution.

1. Go to your google account (https://myaccount.google.com/?hl=en&utm_source=OGB&utm_medium=act&nlr=1)

2.  In the security section go to App password.

3. Select app = Other then it will ask you to Select the app and device you want to generate the app password for, set it to the website, and Click on Generate. It will generate a password.

4. Copy this password and set it in your settings.py

# settings.py

EMAIL_HOST_PASSWORD = 'Type your app password here'

The follow-up comments email looks like this.

How to customize follow-up comments email template?

In your templates folder

1. Create a folder "django_comments_xtd".

2. Inside this folder create a file "email_followup_comment.html"

By default, email_followup_comment.html contains this code. You can add styling (CSS) or bootstrap classes to make it attractive.

<!-- email_followup_comment.html -->
<!-- in case of https, replace every http with https -->

{% load i18n %}<p>Hello {{ user_name }},</p>

<p>{% trans 'There is a new comment following up yours.' %}</p>

<p>{% trans 'Sent by' %}: {{ comment.name }}, {{ comment.submit_date|date:"SHORT_DATE_FORMAT" }}<br/>
<a href="http://{{ site.domain }}{{ comment.content_object.get_absolute_url }}">http://{{ site.domain }}{{ comment.content_object.get_absolute_url }}</a></p>

<p>{% trans 'The comment' %}:<br/>
<i>{{ comment.comment }}</i>
</p>

<p>{% blocktrans with site_domain=site.domain mute_url_short=mute_url|slice:":40" %}Click <a href="http://{{ site_domain }}{{ mute_url }}">http://{{ site_domain }}{{ mute_url_short }}...</a> to mute the comments thread. You will no longer receive follow-up notifications.{% endblocktrans %}</p>
<p>--<br/>
{% trans 'Kind regards' %},<br/>
{{ site }}
</p>

For example, My website email template after adding CSS looks like this.

Source code is available here.

That's it., we're done now I hope this will be helpful to you. On this blog, you can view a live demonstration of this comment section. If you like it please press the clap button, you can also support me by buying me a coffee and in case of any query, comment below in the comment section.

I would greatly appreciate it if you subscribe to my YouTube channel, Let's Code More

 ⋅  12 comments have been posted.
    June 27, 2022, 6:44 p.m. - Arshi Rana  
    You guide very well. The content I was looking for. You made it easy. Expecting more tutorials. Bravo!
    Reply
    June 28, 2022, 7:51 a.m. - Areeba  
    Thanks Arshi for appreciation. I am glad you liked it :)
    Reply
    Feb. 11, 2024, 12:51 a.m. - Pulsedbio  
    The synthesis of nitroethane involves several methods https://pulsedbiofeedbackclinic.com/chemical-marvel-exploring-the-properties-of-79-24-3 besides processes. Industrial Production: Nitroethane is industrially produced by treating propane with nitric acid at exalted temperatures, resulting in the production of different nitro compounds, including nitroethane. The reaction trades 1-nitropropane, 2-nitropropane, nitroethane, and nitromethane as the main products. Chemical Reactions: Nitroethane reacts with an aldehyde or ketone in presence of a base in order forms nitro alcohols, whom have a chance be future dehydrated in order yield nitroalkenes, nitroketones, or amino alcohols. This process predisposed known as the nitroaldol reaction or Henry reaction. Amateur Synthesis Challenges: Nitroethane predisposed sold by chemical suppliers, but despite all of the above the result <a href=https://pulsedbiofeedbackclinic.com/chemical-marvel-exploring-the-properties-of-79-24-3>https://pulsedbiofeedbackclinic.com/chemical-marvel-exploring-the-properties-of-79-24-3</a> its classification as a DEA List I chemical in the US, it predisposed highly not easy for galatansko chemists in order to receive in this compound. Synthesis Methods: Various synthesis methods for nitroethane will need been discussed, covering application of of tech-grade K2CO3, sodium nitrite, besides cetyl-oleic alcohol in all reaction process in order to izgotovlenie nitroethane. Additionally, there are discussions about the challenges besides limitations of a variety synthesis ways, covering safety interests besides the availability of precursor compounds. Historical Use: Nitroethane was previously second hand as all chemical feedstock for the synthesis of the various substances besides consumer goods, including the medicine Pervitin (methamphetamine) besides any other phenethylamines.
    June 27, 2022, 4:04 p.m. - Meher  
    Very well explained 👏
    Reply
    June 28, 2022, 7:52 a.m. - Areeba  
    Thanks Meher :) Please follow us for more content.
    Reply
    Jan. 2, 2023, 1:35 p.m. - django developer  
    i implemented this on my site but the problem im having is the nexted comment but i have to use in container in it since django comments-xtd is making use of bootstrap
    Reply
    June 27, 2022, 1:35 p.m. - Kinza  
    Very well explained 👍
    Reply
    June 27, 2022, 1:48 p.m. - Areeba moderator  
    Thank you Kinza. Don't forget to subscribe our newsletter for more content. Happy coding :)
    Reply
    June 27, 2022, 1:25 p.m. - Michael  
    This is great! Very useful and really easy to follow. I look forward to what comes next.
    Reply
    June 27, 2022, 1:47 p.m. - Areeba moderator  
    I am happy that you liked it.
    Reply
    Nov. 27, 2022, 10:16 p.m. - James Sunday  
    Hello, I tried to implement the comment functionality on my blog but i got this error 'str' object has no attribute '_meta' on my blog post detail page. Can u help?
    Jan. 2, 2023, 1:39 p.m. - django developer  
    What views are you making use of , remember that his is using class based view so try to check your template that is where the error is coming from
claps