How to create a simple blog using Django 3 - part 9

/ #Django

What is a blog without comments? In this part we'll create everything we need for adding and showing comments in our posts.

Creating the model

We have models for posts and categories, but we also need one for our comments. Open up "blog/" and add this code to the bottom:

class Comment(models.Model):
	post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
	name = models.CharField(max_length=255)
	body = models.TextField()

	date_added = models.DateTimeField(auto_now_add=True)

	def __str__(self):
		return '%s - %s' % (,

The model doesn't need too many fields, but all of these are required. The first field is a relation to the post it's commented on. The "on_delete" attribute is set so that if you delete a post, the comments will also be deleted.

To make the comments look a little better in the admin interface, we added the __str__ function. We format a string by joining the title of the post and the name of the submitter.

But we need to tell Django about this model, so go to the command line and write the two following lines:

$ python makemigrations
$ python migrate

Now the database is updated with the information about the comment model.

Creating the comment form

To make this as simple as possible, we're going to use something called ModelForm from Django. Inside the "blog" folder, create a new file called "" and add the following content to it:

from django.forms import ModelForm
from .models import Comment

class CommentForm(ModelForm):
	class Meta:
		model = Comment
		fields = ['name', 'body']

ModelForm automatically generates a form for you when you do this. The form should be based on the model "Comment" and we want only the two fields name and body.

Changing the post detail view

We need to make some changes to the view before we add the comment form to the template. Open up "blog/" and make the following changes:

# Add this line to the top (Import the form we just created)
from .forms import CommentForm

# Replace the entire post_detail view with this
def post_detail(request, post_slug):
	post = Post.objects.get(slug=post_slug)
	categories = Category.objects.all()
	if request.method == 'POST':
		form = CommentForm(request.POST)

		if form.is_valid():
			comment = = post

			form = CommentForm()
		form = CommentForm()
	context = {
		'post': post,
		'categories': categories,
		'form': form
	return render(request, 'blog/templates/detail.html', context)

First, we just import the form we created. There are a few changes to the post_detail view, but it shouldn't be too overwhelming I hope.

We do a check to see if the request method is POST (It's POST when the form is submitted). If it is POST, we assign the "form" variable to the CommentForm and pass in the request. Since "post" is a required field for the comment, we can't just save the form with "". So we check that the form is valid, and if so, we add a new variable called "comment" and assign it to the save function, without commiting it to the database.

After that, we add the post field and save the comment. Below the save method, we reset the form. Ideally you should redirect the user instead.

If the request method is not POST, we just assign the form variable to an empty form.

Showing the form

The last step in the form part is to show it in the template. Open up "blog/templates/detail.html" in your editor and add this code below the post:

<h2>Leave a comment</h2>

<form method="post" action=".">
	{% csrf_token %}
	{{ form.as_p }}

	<input type="submit" class="button is-primary" value="Submit">

And that's it actually. The {% csrf_token %} is generated by Django to prevent form submission from uncertified places. Start the development server and open one of your posts. A form should appear at the bottom. If you add a comment now, don't expect it to be showing there since we haven't added that part yet.

Showing comments

We've come so far, but we still need to show the comments. Open up the "blog/tempates/detail.html" template again and add this code above the comment form:

{% for comment in post.comments.all %}
	<div class="comment">
		<p><b>{{ }} <span class="time">{{ comment.date_added|date:"M d, y h:i" }}</span></b></p>

		<p>{{ comment.body }}</p>
{% endfor %}

That was easy, wasn't it? Since we added a "related_name" to the "post" field in the "comment" model, we can just do "post.comments.all" to get all the comments related to the post we're reading.


Now that we have comments on our blog, it really starts to look like a blog. In the next part of this series, we'll add a simple search.

How to create a simple blog using Django 3 series

Part 1 - Installation
Part 2 - File structure
Part 3 - Database models
Part 4 - Admin interface
Part 5 - Creating some templates
Part 6 - Views and URLs
Part 7 - Category views
Part 8 - Media files
Part 9 - Comments
Part 10 - Search


No comments yet...

Add comment

Subscribe to my newsletter