Form
and ModelForm
. The first one was already used to allow users to share posts via email. Now you need to use ModelForm
because the form needs to be created dynamically based on Comment
. Edit the blog
application’s forms.py
file and add the following lines: from .models import Comment
class CommentForm(forms.ModelForm)
class Meta
model = Comment
fields = ('name', 'email', 'body')
To create a model-based form, you just need to specify which model to take as the basis in the Meta
form class. Django examines the model and builds the form dynamically. Each field in the model has a corresponding default form field type. The way the model fields have been defined is taken into account when validating the form. By default, Django creates a form field for each model field. But you can explicitly tell the framework which fields are needed in the form by using the fields
list or defining which fields to exclude by using the exclude
fields list. For the CommentForm
, name
, email
, and body
will be used because that’s the only thing that needs to be filled in.
Processing ModelForms in views
For simplicity, the post view will be used to create the form instance and process it. Edit the views.py
file, add imports for the Comment
model and CommentForm
, and edit the post_detail
view to look like this:
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 the active comments on this post
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST'
# The comment has been posted
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid()
# Create a Comment object, but don't save it to the database yet
new_comment = comment_form.save(commit=False)
# Assign the current post to the comment
new_comment.post = post
# Save comment in the database
new_comment.save()
else
comment_form = CommentForm()
return return(request,
'blog/post/detail.html',
{'post': post,
'comments': comments,
{ 'new_comment': new_comment,
'comment_form': comment_form})
Let’s break down what’s in the view. The post_detail
view is used to display the post and comments. Use QuerySet to retrieve all active comments:
comments = post.comments.filter(active=True)
This QuerySet starts with the post
object. The manager for related objects defined in comments
is used with the related_name
attribute of the relationship in the Comment
model. The same view is used to allow users to leave comments. The new_comment
variable is initialized by passing it the value None
. It is created when the comment is created. An instance of the form is created with comment_form = CommentForm()
if the view is called with a GET
request. If it is done via POST
, the form instance is created with the submitted data and is validated via the is_valid()
method. If the form is invalid, a template with validation errors is rendered. If the form is correct, the following steps are performed:
- A new
Comment
object is created by calling the form’ssave()
method and assigning it to thenew_comment
variable as follows:new_comment = comment_form.save(commit=False)
The
save()
method creates an instance of the model to which the form is attached and saves it to the database. If it is called withcommit=False
, an instance will be created, but saving to the database will not take place. This is handy when you want to change the object before saving. And this is the next step. Thesave()
method is available forModelForm
, but not forForm
instances because they are not bound to any model. - The current post is assigned to the created comment:
new_comment.post = post
This marks the comment as belonging to that post.
- Finally, the new comment is saved to the database via the
save()
method:new_comment.save()
The view is ready to display and process new comments.