Django Blog: Notifying about new comments by email
Every blogger is interested in comments for his/her blog posts. So do I. Unfortunately there are no so much comments on my blog (only two), but I hope there will be more in future :)
But how could the author of the blog be notified about new comments? One possibility is to create feed for new comments and subscribe to it using your favourite feed reader (f.e. Google Reader). In fact I had been using this approach until recently. But I think that more convenient approach is to be notified by email. Now I am going to describe how I implemented this functionality in my blog.
The problem seems to be simple – just send email after comment object is saved to database. But I am using django.contrib.comments application and can not modify its code.
Fortunately django provides way to hook into process of the object saving. Internally Django (or more strictly speaking post magic-removal version of Django) uses PyDispatch framework – multiple-producer-multiple-consumer signal-dispatching system :) Despite this complex name idea of this framework is really simple: you can produce signals using following method
dispatcher.send(signal=Any, sender=Anonymous,
*args, **kwargs)
and register listeners for the signals using:
dispatcher.connect(receiver, signal=Any, sender=Any,
weak=True)
Check sources of django.dispatch package for more details.
Django ORM framework supports following signals defined in django.db.models.signals package:
| signal | when given signal is sent | args | kwargs |
| pre_init | before model object initialization (from constructor) | positional arguments to init | keyword arguments to init |
| post_init | after object is initialized | None | instance = self |
| pre_save | just before saving object to database | None | instance = self |
| post_save | after saving object to database | None | instance = self |
| pre_delete | just before deleting object from database | None | instance = self |
| post_delete | after deleting object from database | None | instance = self |
For all these signals model class serves as sender.
Now our task becomes very easy – write and register post_save signal listener for FreeComment class:
from django.db import models
from django.db.models import signals
from django.dispatch import dispatcher
from django.core.mail import send_mail
from django.template import Context, loader, Template,
TemplateDoesNotExist
from django.contrib.comments.models import FreeComment
# send mail on comment
def send_comment_by_mail(instance):
comment = instance
if comment.content_type.model_class() != Entry:
return
entry = Entry.objects.get(id__exact = comment.object_id)
# templates for mail subject and body
try:
subject_tmp = loader.get_template("free_comment_subject")
except TemplateDoesNotExist:
subject_tmp = Template('New comment for entry \
"{{ entry.title }}" by "{{ comment.person_name }}"')
try:
body_tmp = loader.get_template("free_comment_body")
except TemplateDoesNotExist:
body_tmp = Template('{{ comment.comment }}')
# send email to the user
ctx = Context({'entry': entry, 'comment': comment})
subject = subject_tmp.render(ctx).decode('utf-8').strip()
body = body_tmp.render(ctx).decode('utf-8')
entry.author.email_user(subject, body)
# connect signal
dispatcher.connect(send_comment_by_mail,
sender = FreeComment,
signal = signals.post_save)
Posted by on July 1, 2006 | development, django
Comments
fonso February 7, 2007 at 12:44 p.m.
Thanks for this! I was just wrapping a view. It never occurs to using signals :)
fonso February 7, 2007 at 12:48 p.m.
Aargh, sorry for my fine Engrish example :(
Matias February 10, 2007 at 11:50 a.m.
Where is the best place to place this code?
Thanks a lot.
ksh February 12, 2007 at 12:15 a.m.
I put this code together with model classes for my Blog (models.py).
Another place to put it that I find rather convenient - settings.py
Greg February 7, 2008 at 2:15 a.m.
It is a bit inappropriate to put it in settings.py, IMHO. That really is only for static content/settings.
kuri April 29, 2008 at 9:24 a.m.
Thanks for this! I was just wrapping a view. It never occurs to using signals :) http://offer.interwebsearch.org
sdasdasd July 9, 2008 at 3:49 p.m.
<a href="http://www.szpengji.com/" title="搬家公司">搬家公司</a>
sdasdasd July 9, 2008 at 3:50 p.m.
Thanks for this! I was just wrapping a view. It never occurs to using
James Bennett July 18, 2008 at 5:34 a.m.
Been there, done that (and more): http://code.google.com/p/django-comment-...
David Avraamides July 14, 2006 at 5:42 a.m.
Very useful post. I wanted to add the same feature to my Django-based blog (http://davidavraamides.net) and you saved me a lot of work!
Thanks,
-Dave