Handling ModelForms in views

We will use the post detail view to instantiate the form and process it in order to keep it simple. Edit the views.py file, add imports for the Comment model and the CommentForm form, and modify the post_detail view to make it look like the following:

from .models import Post, Comment
from .forms import EmailPostForm, CommentForm

def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status='published',
publish__year=year,
publish__month=month,
publish__day=day)

# List of active comments for this post
comments = post.comments.filter(active=True)

new_comment = None

if request.method == 'POST':
# A comment was posted
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
# Create Comment object but don't save to database yet
new_comment = comment_form.save(commit=False)
# Assign the current post to the comment
new_comment.post = post
# Save the comment to the database
new_comment.save()
else:
comment_form = CommentForm()
return render(request,
'blog/post/detail.html',
{'post': post,
'comments': comments,
'new_comment': new_comment,

'comment_form': comment_form})

Let's review what we have added to our view. We used the post_detail view to display the post and its comments. We added a QuerySet to retrieve all active comments for this post, as follows:

comments = post.comments.filter(active=True)

We build this QuerySet, starting from the post object. We use the manager for related objects we defined as comments using the related_name attribute of the relationship in the Comment model.

We also use the same view to let our users add a new comment. Therefore, we initialize the new_comment variable by setting it to None. We will use this variable when a new comment is created. We build a form instance with comment_form = CommentForm() if the view is called by a GET request. If the request is done via POST, we instantiate the form using the submitted data and validate it using the is_valid() method. If the form is invalid, we render the template with the validation errors. If the form is valid, we take the following actions:

  1. We create a new Comment object by calling the form's save() method and assign it to the new_comment variable as follows:
new_comment = comment_form.save(commit=False)

The save() method creates an instance of the model that the form is linked to and saves it to the database. If you call it using commit=False, you create the model instance, but you don't save it to the database yet. This comes in handy when you want to modify the object before finally saving it, which is what we do next.

The save() method is available for ModelForm but not for Form instances, since they are not linked to any model.

  1. We assign the current post to the comment we just created:
new_comment.post = post

By doing this, we are specifying that the new comment belongs to this post.

  1. Finally, we save the new comment to the database by calling its save() method:
new_comment.save()

Our view is now ready to display and process new comments.