Usage overview¶
The goal of django-soapbox is to provide a way to display persistent
messages on either all pages, specific pages, or a subset of pages on
a Django-powered site. To begin using django-soapbox, install it, then add soapbox to your INSTALLED_APPS setting
and run manage.py migrate to install the Message
model.
You can then begin creating Message
instances through the
admin interface, indicating which URLs you’d like them to appear on.
Provided models¶
..currentmodule:: soapbox.models
-
class
Message
¶ The core of django-soapbox is the
Message
model, which represents messages to be displayed on your site. This model has four fields and one important custom method:-
message
¶ A
TextField
containing the text of the message to display. This can be plain text, or can include HTML.
-
is_active
¶ A
BooleanField
(defaults toTrue
) indicating whether the message is currently active; only active messages will be retrieved by the standard helpers built in to django-soapbox.
-
is_global
¶ A
BooleanField
(defaults toFalse
) indicating whether the message is global; a global message does not need to haveurl
(see below) set, and will match any URL.
-
-
class
MessageManager
¶ Also provided on
Message
is a custom manager, accessible as the attributeobjects
, which defines two useful methods:-
active
()¶ Returns a
QuerySet
of allMessage
instances which haveis_active
set toTrue
. This is defined as a customQuerySet
method, so it can also be “chained” with otherQuerySet
methods. For example, the following would retrieve allMessage
instances which are both global and active:Message.objects.filter(is_global=True).active()
Return type: QuerySet
-
Validation requirements¶
While Message
instances are relatively freeform, there are
two requirements you must abide by; failure to do so will result in
validation errors being raised when trying to save the
Message
:
- Each
Message
must either haveis_global
set toTrue
, or specify some URL prefix to match inurl
. - A
Message
cannot have bothis_global
set toTrue
and simultaneously have a URL prefix to match specified inurl
(in other words, aMessage
can be global, or “local” to some URL prefix, but never both at the same time).
Message URL matching¶
The message-retrieval helpers provided in django-soapbox will only
retrieve messages which are active and which match a particular URL
you pass to them; typically, this will be the URL of the current
request. The matching process is case-sensitive and uses the following
algorithm, implemented in the match()
method of
Message
.
- If the
Message
has is_global set toTrue
, immediately returnTrue
. - Strip leading and trailing slashes from the URL, and from the
url
field of theMessage
, and split each on internal slashes to yield a list of path components. - If the list of components from the
url
field of theMessage
is longer than the list from the passed-in URL, immediately returnFalse
. - Return
True
if the list of components from theurl
field, and the corresponding list of components from the beginning of the passed-in URL, are equal. Otherwise, returnFalse
.
This means that a Message
will match not only a URL which is
an exact match for its own url
, but also any URL of
which its url
is a prefix. So, for example, if the
url
field contained /foo/, it would match on
/foo/ and on /foo/bar/.
Retrieving and displaying messages¶
There are two helpers built in to django-soapbox for retrieving and displaying messages in templates.
One is a context processor, which will add a variable
soapbox_messages to the context of any template rendered with a
RequestContext
(required in order to have
access to the request path to determine the URL). To enable it, add
soapbox.context_processors.soapbox_messages to the context
processors enabled on your site. See the Django template options
documentation
for notes on how to do this.
If you prefer to have more fine-grained control of where messages will be retrieved and displayed, django-soapbox provides a template tag, get_soapbox_messages which can retrieve messages for a given URL and place them into a variable in the context. The syntax of the tag is:
{% get_messages_for_page [url] as [varname] %}
To use the tag, first add {% load soapbox %} to the template to load the django-soapbox template tag library, then call the get_messages_for_page tag, passing a URL – either a string, or a template variable which the tag will resolve – and the name of the context variable you’d like the message to be placed into. For example (presuming you have a context processor enabled which exposes the current HTTP request to your template):
{% load soapbox %}
{% get_messages_for_page request.path as soapbox_messages %}
{% for message in soapbox_messages %}
<p>Important message: {{ message }}</p>
{% endfor %}
What django-soapbox is not¶
Importantly, django-soapbox is not a system for displaying one-time “flash”-type notifications to an individual user; for that, use Django’s built-in message framework. It also is not a system for users to send messages to each other; for that, email or a custom user-message tool is more appropriate.
Instead, django-soapbox is for displaying messages to all users, on any URLs the messages match, each time they visit those URLs. Most often this is useful for site-wide or section-specific announcements all users need to see.
Security considerations¶
The tools provided in django-soapbox are designed around the
assumption that only trusted administrators of your site will be
permitted to create Message
instances. In particular, a
Message
will, by default, mark its contents as safe for display,
and so the Django template system will not perform autoescaping of
the contents. This is useful for allowing HTML messages – for
example, containing links to longer announcements on their own pages
– but if opened to arbitrary or untrusted users would be a serious
cross-site scripting vulnerability
Because of this, it is recommended that you only use the Django administrative interface to create Message instances, and that you carefully restrict the soapbox.add_message permission to only a small number of trusted administrators.