I recently had to implement a way to send notifications (using the excellent django-notification app developed by James Tauber) to users whose content is commented on in my Django web app. However, I wanted the owner/creator of the original content to get a more customized notification message. For example, if the model instance being commented on was an idea from an idea sharing app, I would like the notifications to look something like:
John Smith commented on your idea – “Switching to a better version control system”:
That’s a brilliant idea. I totally agree with you. Let’s make this happen.
Looks a lot better than just: “John Smith commented on something.”
Okay, so the first thing we need to do is to define the notice type for comments. Here are the values I used for my notice type:
- label: comment_posted
- display: Comment Posted
- description: someone posted a comment for your content
from django.db.models import signals, get_app
from django.utils.translation import ugettext_noop as _
from django.core.exceptions import ImproperlyConfigured
try:
notification = get_app( 'notification' )
def create_notice_types( app, created_models, verbosity, **kwargs ):
notification.create_notice_type( 'comment_posted',
_( 'Comment Posted' ),
_( 'someone posted a comment for your content' ) )
signals.post_syncdb.connect( create_notice_types, sender = notification )
except ImproperlyConfigured:
print 'Skipping creation of NoticeTypes as notification app not found'
The next step is to create a signal handler and wire it to the post_save signal for the Comment model.
from django.db.models import signals
from django.contrib.comments.models import Comment
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext as _
from django.core.exceptions import ImproperlyConfigured
from django.db.models import get_app
try:
notification = get_app( 'notification' )
except ImproperlyConfigured:
notification = None
# valid content types
VALID_CTYPES = [ 'link', 'note', 'update' ]
def send_comment_notification( sender, **kwargs ):
# no point in proceeding if notification is not available
if not notification:
return
if 'created' in kwargs:
if kwargs[ 'created' ] == True:
# get comment instance
instance = kwargs[ 'instance' ]
# get comment's content object and its ctype
obj = instance.content_object
ctype = ContentType.objects.get_for_model( obj )
# check for valid content types
if ctype.name not in VALID_CTYPES:
return
# for customized notification message
if ctype.name == 'link':
type = _( 'your link' )
descr = obj.link
elif ctype.name == 'note':
type = _( 'your note' )
descr = obj.title
elif ctype.name == 'update':
type = _( 'your status update' )
descr = obj.update
# send notification to content owner
if notification:
data = {
'comment': instance.comment,
'user': instance.user,
'type': type,
'descr': descr,
}
# notification is sent to the original content object
# owner/creator
notification.send( [ obj.user ], 'comment_posted', data )
# connect signal
signals.post_save.connect( send_comment_notification, sender = Comment )
Nothing fancy or complicated here. Some things to note:
- I created a list of content type names called VALID_CTYPES which I use to control which content types trigger the creation of a custom notification.
- Based on the content type’s name, I define some text that will be used for in the notification message (type).
- I also assign a descriptive name of the item in question (descr). The descriptive name should map to whatever field in the model instance that best describes that instance. You can also use __unicode__() if you wish. You just have to make sure that it is defined in the model class and is suited for display in the notification message.
- The notification is only sent to the owner/creator of the content being commented on.
Finally, we create a simple template for the notification e-mail and put it in templates/notification/comment_posted/:
{% load i18n %}
{% blocktrans with comment as comment and type as type and descr as descr and user.get_full_name as user %}
{{ user }} commented on {{ type }} - "{{ description }}":
{{ comment }}
{% endblocktrans %}
There you have it. Some food for thought:
- In the code above, I only send the notification to the owner/creator of the content. However, you could easily add some code to grab a list of all the users who previously commented on the same content object and spam them as well (ala Facebook)!
- If you have permalinks defined for your models, you could pass the actual content object to the notification template and use get_absolute_url() to display a direct link to the object’s view.
Customized comment notifications from Django
I recently had to implement a way to send notifications (using the excellent django-notification app developed by James Tauber) to users whose content is commented on in my Django web app. However, I wanted the owner/creator of the original content to get a more customized notification message. For example, if the model instance being commented on was an idea from an idea sharing app, I would like the notifications to look something like:
Looks a lot better than just: “John Smith commented on something.”
Okay, so the first thing we need to do is to define the notice type for comments. Here are the values I used for my notice type:
from django.db.models import signals, get_app from django.utils.translation import ugettext_noop as _ from django.core.exceptions import ImproperlyConfigured try: notification = get_app( 'notification' ) def create_notice_types( app, created_models, verbosity, **kwargs ): notification.create_notice_type( 'comment_posted', _( 'Comment Posted' ), _( 'someone posted a comment for your content' ) ) signals.post_syncdb.connect( create_notice_types, sender = notification ) except ImproperlyConfigured: print 'Skipping creation of NoticeTypes as notification app not found'The next step is to create a signal handler and wire it to the post_save signal for the Comment model.
from django.db.models import signals from django.contrib.comments.models import Comment from django.contrib.contenttypes.models import ContentType from django.utils.translation import ugettext as _ from django.core.exceptions import ImproperlyConfigured from django.db.models import get_app try: notification = get_app( 'notification' ) except ImproperlyConfigured: notification = None # valid content types VALID_CTYPES = [ 'link', 'note', 'update' ] def send_comment_notification( sender, **kwargs ): # no point in proceeding if notification is not available if not notification: return if 'created' in kwargs: if kwargs[ 'created' ] == True: # get comment instance instance = kwargs[ 'instance' ] # get comment's content object and its ctype obj = instance.content_object ctype = ContentType.objects.get_for_model( obj ) # check for valid content types if ctype.name not in VALID_CTYPES: return # for customized notification message if ctype.name == 'link': type = _( 'your link' ) descr = obj.link elif ctype.name == 'note': type = _( 'your note' ) descr = obj.title elif ctype.name == 'update': type = _( 'your status update' ) descr = obj.update # send notification to content owner if notification: data = { 'comment': instance.comment, 'user': instance.user, 'type': type, 'descr': descr, } # notification is sent to the original content object # owner/creator notification.send( [ obj.user ], 'comment_posted', data ) # connect signal signals.post_save.connect( send_comment_notification, sender = Comment )Nothing fancy or complicated here. Some things to note:
Finally, we create a simple template for the notification e-mail and put it in templates/notification/comment_posted/:
{% load i18n %} {% blocktrans with comment as comment and type as type and descr as descr and user.get_full_name as user %} {{ user }} commented on {{ type }} - "{{ description }}": {{ comment }} {% endblocktrans %}There you have it. Some food for thought: