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.
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:
- 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
- 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.
- Or use easy_install (read more about easy_install):
- Do easy_install django-comments-xtd
- Optionally, if you want to allow comments written in markup languages like Markdown or reStructuredText, install django-markup.
Configuring Django-comments-xtd comprehends the following steps:
- If you allow comments written in markup languages add django_markup to INSTALLED_APPS too.
- 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
- 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
Optionally you can add an extra setting to control Django-comments-xtd behaviour (see Settings), but it has a sane default.
Workflow described in 4 actions:
- 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.
- Renders comments/preview.html either with the comment preview or with form errors if any.
- If there were form errors it does the same as in point 2.
- Otherwise creates an instance of TmpXtdComment model: an in-memory representation of the comment.
- 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:
- If the user is authenticated or confirmation by email is not required (see Settings):
- An instance of XtdComment hits the database.
- 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.
- 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.
- Pass control to the next parameter handler if any, or render the comments/posted.html template:
- If the instance of XtdComment has already been created, redirect to the the comments’s absolute URL.
- 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).
- Checks the secured token in the URL. If it’s wrong returns a 404 code.
- Otherwise checks whether the comment was already confirmed, in such a case returns a 404 code.
- 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.
- Otherwise an instance of XtdComment finally hits the database, and
- An email notification is sent to previous comments followers telling them about the new comment following up theirs.
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:
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).
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.