Tutorial

Django-comments-xtd is a reusable app that relies on its own code and doesn’t require any other third party app, just the built-in Django Comments Framework.

Installation

Installing Django-comments-xtd is as simple as checking out the source and adding it to your project or PYTHONPATH.

Use git, pip or easy_install to check out Django-comments-xtd from Github or get a release from PyPI:

  1. Use git to clone the repository, and then install the package (read more about git):
  • git clone git://github.com/danirus/django-comments-xtd.git and
  • python setup.py install
  1. Or use pip (read more about pip):
  • Do pip install django-comments-xtd, or
  • Edit your project’s requirements file and append either the Github URL or the package name django-comments-xtd, and then do pip install -r requirements.
  1. Or use easy_install (read more about easy_install):
  • Do easy_install django-comments-xtd
  1. Optionally, if you want to allow comments written in markup languages like Markdown or reStructuredText, install django-markup.

Configuration

Configuring Django-comments-xtd comprehends the following steps:

  1. Add 'django.contrib.comments' and 'django_comments_xtd' to your INSTALLED_APPS setting.
  • If you allow comments written in markup languages add django_markup to INSTALLED_APPS too.
  1. Add COMMENTS_XTD_CONFIRM_EMAIL = True to the settings file in order to require comment confirmation by email.
  1. Add url(r'^comments/', include('django_comments_xtd.urls')) to your urls.py.
  2. Create a comments directory in your templates directory and copy the default templates from the Django Comments Framework that you want to customise. Maybe the following:
  • comments/list.html used by templatetag render_comments_list
  • comments/form.html used by templatetag render_comment_form
  • comments/preview.html used to preview the comment or when there are form errors
  • comments/posted.html rendered after comment is sent
  1. To customise how templatetag render_last_xtdcomments renders comments, copy the template file django_comment_xtd/comment.html to any of the following targets in your templates directory:
  • django_comment_xtd/<app>/<model>/comment.html to customise them for the given <app>.<model>
  • django_comment_xtd/<app>/comment.html to customise them for all <app> models
  • django_comment_xtd/comment.html to customise all your site comments at once
  1. Run python manage.py syncdb to create the django_comments_xtd_xtdcomment table.

Optionally you can add an extra setting to control Django-comments-xtd behaviour (see Settings), but it has a sane default.

Workflow

Workflow described in 4 actions:

  1. The user visits a page that accepts comments. Your app or a 3rd. party app handles the request:
  1. Your template shows content that accepts comments. It loads the comments templatetag and using tags as render_comment_list and render_comment_form the template shows the current list of comments and the post your comment form.
  1. The user clicks on preview. The Django Comments Framework post_comment view handles the request:
  1. Renders comments/preview.html either with the comment preview or with form errors if any.
  1. The user clicks on post. The Django Comments Framework post_comment view handles the request:
  1. If there were form errors it does the same as in point 2.
  2. Otherwise creates an instance of TmpXtdComment model: an in-memory representation of the comment.
  3. Send signal comment_will_be_posted and comment_was_posted. The django-comments-xtd receiver on_comment_was_posted receives the second signal with the TmpXtdComment instance and does as follows:
  1. If the user is authenticated or confirmation by email is not required (see Settings):
  1. An instance of XtdComment hits the database.
  2. An email notification is sent to previous comments followers telling them about the new comment following up theirs. Comment followers are those who ticked the box Notify me of follow up comments via email.
  1. Otherwise a confirmation email is sent to the user with a link to confirm the comment. The link contains a secured token with the TmpXtdComment. See below Creating the secure token for the confirmation URL.
  1. Pass control to the next parameter handler if any, or render the comments/posted.html template:
  1. If the instance of XtdComment has already been created, redirect to the the comments’s absolute URL.
  2. Otherwise the template content should inform the user about the confirmation request sent by email (see the multiple models demo site templates directory for an example).
  1. The user clicks on the confirmation link, in the email message. Django-comments-xtd confirm view handles the request:
  1. Checks the secured token in the URL. If it’s wrong returns a 404 code.
  2. Otherwise checks whether the comment was already confirmed, in such a case returns a 404 code.
  3. Otherwise sends a confirmation_received signal. You can register a receiver to this signal to do some extra process before approving the comment. See Signal and receiver. If any receiver returns False the comment will be rejected and the template django_comments_xtd/discarded.html will be rendered.
  4. Otherwise an instance of XtdComment finally hits the database, and
  5. An email notification is sent to previous comments followers telling them about the new comment following up theirs.

Creating the secure token for the confirmation URL

The Confirmation URL sent by email to the user has a secured token with the comment. To create the token Django-comments-xtd uses the module signed.py authored by Simon Willison and provided in Django-OpenID.

django_openid.signed offers two high level functions:

  • dumps: Returns URL-safe, sha1 signed base64 compressed pickle of a given object.
  • loads: Reverse of dumps(), raises ValueError if signature fails.

A brief example:

>>> signed.dumps("hello")
'UydoZWxsbycKcDAKLg.QLtjWHYe7udYuZeQyLlafPqAx1E'

>>> signed.loads('UydoZWxsbycKcDAKLg.QLtjWHYe7udYuZeQyLlafPqAx1E')
'hello'

>>> signed.loads('UydoZWxsbycKcDAKLg.QLtjWHYe7udYuZeQyLlafPqAx1E-modified')
BadSignature: Signature failed: QLtjWHYe7udYuZeQyLlafPqAx1E-modified

There are two components in dump’s output UydoZWxsbycKcDAKLg.QLtjWHYe7udYuZeQyLlafPqAx1E, separatad by a ‘.’. The first component is a URLsafe base64 encoded pickle of the object passed to dumps(). The second component is a base64 encoded hmac/SHA1 hash of “$first_component.$secret”.

Calling signed.loads(s) checks the signature BEFORE unpickling the object -this protects against malformed pickle attacks. If the signature fails, a ValueError subclass is raised (actually a BadSignature).

Signal and receiver

Django-comments-xtd sends a signal in addition to the signals sent by the Django Comments Framework.

Django-comments-xtd allows the user to receive the signal:

  • confirmation_received: Sent when the user clicks on the confirmation link and before the XtdComment instance is created in the database.

You might want to register a receiver for this signal. An example function receiver might check the datetime a user submitted a comment and the datetime the confirmation URL has been clicked. Say that if the difference between them is over 7 days the message should be discarded with a graceful “sorry, too old comment” template.

Extending the demo site with the following code would do the job:

#----------------------------------------
# append the code below to demo/views.py:

from datetime import datetime, timedelta
from django_comments_xtd import signals

def check_submit_date_is_within_last_7days(sender, data, request, **kwargs):
    plus7days = timedelta(days=7)
    if data["submit_date"] + plus7days < datetime.now():
        return False
signals.confirmation_received.connect(check_submit_date_is_within_last_7days)


#-----------------------------------------------------
# change get_comment_create_data in django_comments_xtd/forms.py to cheat a
# bit and make Django believe that the comment was submitted 7 days ago:

def get_comment_create_data(self):
    from datetime import timedelta                                     # ADD THIS

    data = super(CommentForm, self).get_comment_create_data()
    data['followup'] = self.cleaned_data['followup']
    if settings.COMMENTS_XTD_CONFIRM_EMAIL:
        # comment must be verified before getting approved
        data['is_public'] = False
    data['submit_date'] = datetime.datetime.now() - timedelta(days=8)  # ADD THIS
    return data

Try the demo site again and see that the django_comments_xtd/discarded.html template is rendered after clicking on the confirmation URL.

Table Of Contents

Previous topic

Demo projects

Next topic

Templatetags

This Page