I’m proceeding in my quest to learn how to create a Django application using Pinax as a base. I’m writing a sample paste bin application called Oxybeles. It’s main feature will be the ability to send pasted items to another user and to receive new pasted items as responses.
I want a user to be notified when another user sends an item or responds to one. So I went looking how the applications integrated into Pinax do that. For instance, the Inbox feature in Pinax can be used to send a message to another website user:
The Propose Swap feature of the Swaps application will also notify another user:
Those notifications can be seen in the Notices feature of the Inbox:
By inspecting the source code for these features, I found out that they use the django-notification app. There is some documentation about it on the Pinax project website. So, I started following it.
Creating notice types
Following samples and documentation, I created the file apps/oxybeles/management.py that creates notice types at syncdb time:
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(
"pasteditem_received",
_("Pasted Item Received"),
_("you have received a pasted item"))
notification.create_notice_type(
"pasteditem_sent",
_("Pasted Item Sent"),
_("you sent a pasted item"))
signals.post_syncdb.connect(create_notice_types, sender=notification)
except ImproperlyConfigured:
print "Skipping creation of NoticeTypes as notification app not found."
Then I ran syncdb:
$ python manage.py syncdb
Created pasteditem_received NoticeType
Created pasteditem_sent NoticeType
Notification templates
Then I created the templates that will be used to format the notifications. Each set is composed by three files: short.txt, full.txt and notice.html. For each notification type I created a directory under apps/oxybeles/templates/notification. For instance:
apps/oxybeles/templates/notification/pasteditem_received/full.txt:
{% load i18n %}{% blocktrans with pasted_item.get_absolute_url as pasted_item_url %}
{{ sender }} sent you a pasted item:
http://{{ current_site }}{{ pasted_item_url }}{% endblocktrans %}
apps/oxybeles/templates/notification/pasteditem_sent/notice.html:
{% load i18n %}
{% blocktrans with pasted_item.get_absolute_url as pasted_item_url %}
You sent a <a href="{{ pasted_item_url }}">pasted item</a> to {{ recipient }}.
{% endblocktrans %}
Sending notification
After that I should be able to notify a user when someone sends a pasted item. The first step is to add an appropriate field to the pasted item detail template:
templates/oxybeles/pasteditem_detail.html:
...
<h1>Pasted Item</h1>
<pre>
<p>{{ object.text }}</p>
</pre>
<div id="basic-form">
<fieldset>
<legend>{% trans "Send Item" %}</legend>
<form id="pastebin_send_form" method="POST" action="">
<div>{{ form.non_field_errors }}</div>
<div>{{ form.recipient.errors }}</div>
<div>Send to another user: {{ form.recipient }}</div>
<div><input type="submit" value="send" class="button" /></div>
<input type="hidden" name="action" value="send" />
<input type="hidden" name="uuid" value="{{ object.uuid }}" />
</form>
</fieldset>
</div>
...
And a form to deal with the submitted data:
In apps/oxybeles/forms.py:
...
class SendItemForm(forms.Form):
uuid = forms.CharField(max_length=36)
recipient = forms.CharField(max_length=30)
...
The view that shows a pasted item now will also act on this form’s data:
In apps/oxybeles/views.py:
...
def detail(request, uuid, form_class=SendItemForm, template_name='oxybeles/pasteditem_detail.html'):
form = form_class()
if request.method == 'POST':
if request.POST["action"] == "send":
form = form_class(sender=request.user, data=request.POST)
if form.is_valid():
form.save()
request.user.message_set.create(
message=ugettext("The pasted item was sent."))
url = form.pasted_item.get_absolute_url()
return HttpResponseRedirect(url)
pasted_item = get_object_or_404(PastedItem, uuid=uuid)
return render_to_response(template_name,
{ 'object': pasted_item, 'form': form },
context_instance=RequestContext(request))
detail = login_required(detail)
...
The form.save() function will notify the recipient and also the sender.
In apps/oxybeles/forms.py:
...
def save(self):
self.pasted_item = self.cleaned_data['uuid']
self.recipient_user = self.cleaned_data['recipient']
if notification:
notification.send([self.sender], "pasteditem_sent",
{'pasted_item': self.pasted_item,
'recipient': self.recipient_user,})
notification.send([self.recipient_user], "pasteditem_received",
{'pasted_item': self.pasted_item,
'sender': self.sender,})
...
django-notification does all the work. It creates the notifications and will also mail the user if the preference is enabled. The email will only be sent when we run manage.py send_mail, though.
Now I can send a pasted item I’m seeing:
Those sendings are recorded as notifications:
And the recipient is notified when someone sends an item:
Pinax is an integrated collection of selected reusable Django apps, and I’m starting to learn how to leverage it. Seems pretty nice so far.
The code for this article is hosted at GitHub. Feedback is welcome.