A Detailed Django Tutorial: Blog Basics Part IV

 

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.).

Table of Contents



Comments

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.

Listing page

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.

Detail Page

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.



Final Result

Homepage

Individual post page with comments form.



Wrapping Up

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):

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

Related posts:

  1. A Detailed Django Tutorial: Blog Basics Part II
  2. A Detailed Django Tutorial: Blog Basics Part III
  3. Django Tutorial: Blog Basics
  4. Django Python Framework
  5. Ruby on Rails To Do List Tutorial


Written by Brenley Dueck

 

20 Responses to “A Detailed Django Tutorial: Blog Basics Part IV”

  1. shane sponagle Says:

    April 6th, 2009 at 1:55 pm

    I am sorry to see this series come to an end. Great stuff, thanks :)

  2. Django Blog Tutorial | Blog of Jeff Says:

    April 6th, 2009 at 2:22 pm

    [...] Part 4 [...]

  3. Jeff Says:

    April 6th, 2009 at 3:10 pm

    Thanks :)

    I do plan on writing more Django tutorials though.

  4. Django Blog Tutoral Completed | Blog of Jeff Says:

    April 6th, 2009 at 3:40 pm

    [...] (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 [...]

  5. qwertyt Says:

    April 8th, 2009 at 10:45 am

    Great tutorial!!!

    Thanks!

    More tutos please…

  6. Daemian Mack Says:

    June 19th, 2009 at 8:05 am

    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.

  7. Chuck Says:

    July 16th, 2009 at 7:08 pm

    Nice work!

  8. n3ls0n Says:

    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…

  9. Peters Django-Links – Der Schockwellenreiter Says:

    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 [...]

  10. Joseph Says:

    March 11th, 2010 at 7:56 am

    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

  11. David Says:

    April 11th, 2010 at 12:42 am

    Thanks for the great tutorials! Probably the best I’ve come across so far.

  12. Willy Says:

    August 9th, 2010 at 5:37 am

    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. :/

  13. Willy Says:

    August 9th, 2010 at 4:30 pm

    Hmmm, now I’m getting a 403 error because I don’t have a proper CSRF in the comment field.

  14. binyu Says:

    September 9th, 2010 at 8:52 pm

    Invalid block tag: ‘get_comment_list’, expected ‘endblock’ or ‘endblock comment’
    in posts_detail.html?? why?

  15. binyu Says:

    September 10th, 2010 at 1:18 am

    solved! add {% load comments %} before that & after include tag:)

  16. teioch Says:

    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.

  17. Paul Says:

    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

  18. Jeffry Granstaff Says:

    January 4th, 2011 at 5:01 pm

    Where can I find your RSS feed please?

  19. Vinod Patidar Says:

    May 7th, 2011 at 5:43 am

    Nice Work! keep it up!

  20. Anu Says:

    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

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 
connect with me!