This is the last part of this 4 part series by Jeff Hui. If you wish, you can download the entire tutorial without having it split up.
Today we’ll be learning the gist of Django, a pythonic web framework. In the spirit of a stereotypical web framework tutorial, we’ll produce a primitive blog with the minimal amount of code possible. Yellow background color text indicates text to be entered into a command line/terminal and blue indicates code. If you’ve followed my django screencast, you’ll be familiar with the most of what this tutorial covers. However, I’ll explain the code in this tutorial in more depth than I did in the screencast. If you like to know what everything does, this article is for you.
If you’ve never dealt with (or even seen) python code before, I recommend skimming through python’s official tutorial. The most notable difference between python and most other languages is that tabs/spaces are used to indicate code blocks. So an if statement would look something like this:
if myvariable == True:
print “myvariable is True”
print “Always printed”
One other thing to note is that boolean variables are True and False (case-sensitive). It’s also a good idea to dust off your terminal / command line skills (cd, ls, etc.).
What’s a blog without comments? Good thing Django provides built-in functionality to implement this. In the typical application installation fashion, we add the follow below ‘django.contrib.admin’ in settings.py under INSTALLED_APPS.
‘django.contrib.comments’,
Then we need to map it to a url. For simplicity, we’ll edit our project’s urls.py and add the following under urlpatterns:
(r’^comments/’, include(‘django.contrib.comments.urls’)),
Now we can start adding comments to our posts. The comments application adds custom template tags. To load them, you use {% load comments %} before using custom template tags.
Edit posts/post_list.html to match the following:
{% extends ‘base.html’ %}
{% load comments %}
{% block content %}
{% for object in object_list %}
<hr/>
{% include ‘posts/_post.html’ %}
{% get_comment_count for object as comment_count %}
<small>{{ comment_count }} comment{{ comment_count|pluralize }}</small>
{% endfor %}
{% endblock %}
We load the comments template tags and then get the number of comments for the given post object and then display it out. You probably noticed the pluralized filter. In this case, the pluralize filter accepts a numeric value and outputs s if the value isn’t 1. For words that aren’t pluralized with an s can be expressed as: fish{{ fish_count|pluralize:”es” }} or famil{{ family_count|pluralize:”y,ies” }}. The colon represents a parameter which can be accepted by the filter. At most, a filter can accept one additional parameter other than the incoming variable from the left.
Edit post_detail.html and add the following after the include tag:
{% get_comment_list for object as comment_list %}
<h3>Comments</h3>
{% for comment in comment_list %}
<div id=”comment_{{ comment.id }}”>
<p>{{ comment.comment }}</p>
<small>{{ comment.name }}</small>
</div>
{% empty %}
<p>It’s pretty quiet here… be first to comment!</p>
{% endfor %}
The get_comments_list tag does what it says. It retrieves all comments for a particular model to store in comment_list. Using comment_list, like object_list in post_list.html, we can iterate over each comment using a for loop. You’ll also notice the empty template tag. It is similar to an else clause of an if statement. For a for loop, if there are no items in the list, the empty block is displayed.
Finally, we’ll add a comment form so users can post new comments. Append the following:
<hr/>
<h3>Your comment</h3>
{% get_comment_form for object as form %}
<form action=”{% comment_form_target %}?next={% url post object.id %}” method=”post”>
{{ form.content_type }}
{{ form.object_pk }}
{{ form.timestamp }}
{{ form.security_hash }}
<p style=”display:none”><label for=”id_honeypot”>Leave blank</label>{{ form.honeypot }}</p>
<p>
<label for=”id_name”>Name</label>
{{ form.name }}
</p>
<p>
<label for=”id_comment”>Comment</label>
{{ form.comment }}
</p>
<p><input type=”submit” name=”post” value=”Post” /></p>
</form>
As you can see, the comments for also provides the get_comment_form template tag. This returns a form object from a model object to help us display forms. Since we’re a bit lazy on the html we can just output fields which will generate an input form. The first four fields: content_type, object_pk, timestamp, security_hash are hidden fields that the comments application utilizes when creating comments.
content_type is a specific Django feature that allows a model to relate to any other model. Content types are basically a ForeignKey Field to any model, which is pretty handy to generalize a model. Using Content Types, tagging and categories can be easily implement as an individual application without bloating our post application. But those features are out of scope of this application.
object_pk is the primary key value of the specific object to relate to (which is our post id). timestamp is self explanatory. security_hash is used by the comments framework to check for form tampering by spammers. The honeypot field is similar, filling this out will automatically mark the comment as spam. But this input field is of type text and therefore we should hide it via CSS.
The next two fields we add are the regular fields that the user can enter to fill out. There are also other fields we didn’t use: email and url which you can include if you wanted, but our comment form is no-frills, so we’ll only ask for name and comment.


This tutorial is already getting longer than I expected, so I’ll have to wrap it up a bit short. But check out the detailed, hand-written Django Documentation. Besides better styling, other things we could add are (in no particular order):
Writing your own form classes (See Working with Forms)
Feel free to leave comments, twitter me up, or email me. See you until the next tutorial.
This has us come to the end of this in-depth tutorial. If you liked it please subscribe to our RSS Feed
I am sorry to see this series come to an end. Great stuff, thanks ![]()
[...] Part 4 [...]
Thanks ![]()
I do plan on writing more Django tutorials though.
[...] (and don’t check the site). All the Django Blog Tutorials have been posted. You can go to Part 4 and download its entirety if you haven’t been following [...]
Great tutorial!!!
Thanks!
More tutos please…
Thanks — nice quick intro to Django.
Walking through this tutorial, I think an oversight may have occurred somewhere between parts III and IV; it seems the posts/post_detail.html template needs the {% load comments %} tag in order to access get_comment_list. At least, that’s the bit that fixed my template errors here on Django trunk.
Nice work!
November 18th, 2009 at 1:32 pm
This looks like a nice tutorial, but where are the images and sample code. The links are broken…
December 15th, 2009 at 5:42 am
[...] Detailed Django Tutorial: Blog Basics Part IV. Etwas verwirrend in der Navigation (wenn man im Inhaltsverzeichnis auf Installation klickt, landet [...]
Just thought I would mention, because I was stupid enough to miss it, make sure you run syncdb again after adding a new app to settings.py
Thanks for the great tutorials! Probably the best I’ve come across so far.
So I was going through your tutorial and I think I found a small issue. I am getting errors because of your {% url %} tags.
TemplateSyntaxError
Caught NoReverseMatch while rendering: Reverse for 'post.object.id' with arguments '()' and keyword arguments '{}' not found.
Any idea what it could be? I’ve been looking at the Django Documentation but I don’t see if it’s an issue with your tutorial being written on an older version or not. :/
Hmmm, now I’m getting a 403 error because I don’t have a proper CSRF in the comment field.
September 9th, 2010 at 8:52 pm
Invalid block tag: ‘get_comment_list’, expected ‘endblock’ or ‘endblock comment’
in posts_detail.html?? why?
September 10th, 2010 at 1:18 am
solved! add {% load comments %} before that & after include tag:)
November 19th, 2010 at 5:43 am
Nice tutorial, but a few details seem to have been overlooked. For people who know a bit of Django already I’m sure these bits are easy and it might be assumed that people just know this. On my part, having never touched Django before it got a bit confusing.
1) I can’t seem to see you talk about how you can tell django that the formfields like e-mail is optional. I at least get a message that the e-mail field must be filled out.
2) To get the form to working I had to go into settings.py and input ‘django.middleware.csrf.CsrfResponseMiddleware’, into the MIDDLEWARE_CLASSES field, as only CsrfViewMiddleware is input there by default.
November 22nd, 2010 at 8:41 am
Hey teioch,
thanks a lot for the comment. I couldn’t figure out how to get the comment framework working your hint at adding “django.middleware.csrf.CsrfResponseMiddleware” really helped me out. Looking at documentation and tutorials I haven’t seen that that would be required, so I am wondering if either
a) The django tutorial writers suffer from some collective amnesia or
b) It shouldn’t be required but is for some reason on our machines (??).
Anyway, it is working now, thanks a million.
P
Where can I find your RSS feed please?
Nice Work! keep it up!
December 11th, 2011 at 11:49 am
This is very gud tuitorial.helped me alot to develop my blog.please describe more about templating in blog
Twitter
Follow me on Twitter to keep up to date!
RSS Feed
Keep up with all of our updates by subscribing to our RSS feed!
FaceBook
Join our group on Facebook and become a fan of us!