Code


Version 39 (modified by alilozanoc@…, 2 years ago) (diff)

Add new messages option.

Message Passing For Anonymous Users

Proposal for 1.2: Django should include a contrib app, independent of contrib.auth, that facilitates message passing to anonymous users.

For more information see:

Justification

Reasons why an alternative to the existing functionality (user.message_set.create) is needed:

  • It's not possible to create messages for anonymous users
  • If the same Django user is logged in twice on different computers simultaneously, they see each others' messages
  • User messages may get wiped even if they're not actually displayed to the user fixed in r11623
  • High-load sites want to avoid the unneeded database or cache usage

Reasons why a standard needs to be endorsed by Django and a 3rd party app will not suffice:

  • The built-in implementation is broken for a large set of use cases (above); the fact that Django actively encourages this method of messaging is a bad thing
  • Reusable apps don't know what 3rd party system to use and hence cannot rely on providing session feedback

The Existing API

It seems to be the consensus on the mailing list that we have no desire to maintain two messaging APIs in the core and the proposed app will adequately replace all current uses of the existing message API. It has been noted by several people, therefore, that we need a deprecation plan for removing the old API that makes the transition easy for any apps currently using it.

There are several parts to the user message API, each with different options for transition:

  • models.User.message_set.create(message): because this is a just a related manager on a model, and we don't have access to the request (or much else) inside the create() method, it's not possible to override this method with one that stores messages in the new session or cookie backend. It is, however, completely feasible to retrieve and display any messages set in the user Message model from the new app (see below).
  • {{ messages }}: Since this is set in a context processor, we can replace this variable in the template context with one that will lazily wrap messages stored in the user Message model and messages stored in the newer session and cookie backends.
  • models.User.get_and_delete_messages(): As with message_set.create, it is not possible to override this method with one that can retrieve messages from the proposed session and cookie backends. In the transition API, however, it will continue to retrieve (and delete) messages stored in the user Message model via message_set.create (as it has in the past).

Transition Plan

What follows is a rough plan of how to introduce the new API and deprecate the existing one. Some details are still missing and the plan needs to be fleshed out further in the coming days/weeks.

  • Django 1.2
    • Introduce the proposed messaging app
    • Replace {{ messages }} with lazily loaded messages from both the old (user message) and new (session/cookie) storages
    • Deprecate the existing API and mark it as such in the documentation. Retain the same functionality. Raise a PendingDeprecationWarning when used.
    • Update contrib apps (auth and admin) and generic views (create_object, update_object, and delete_object) in Django to use the new API
  • Django 1.3
    • Retain the same functionality in the old API, but raise a DeprecationWarning when it is used
  • Django 1.4
    • Remove the old API. This includes the Message model and any methods in contrib.auth that use it (such as get_and_delete_messages).
    • Remove the old API from the documentation.

Existing 3rd Party Apps

There are a number of good, pre-existing applications out there that support more robust functionality, so there is no need to re-implement a solution from scratch for inclusion in Django. The existing solutions can be combined or modified to meet Django's needs. This section is meant to evaluate some of the different session/cookie message/notification engines out there for potential inclusion in Django as a contrib app. It is a work in progress so please contribute (your notification engine here) or other changes as you see fit.

Criteria

Technical criteria necessary for inclusion in the core:

  • Support message passing for anonymous users
  • Use the session only as a fallback: Avoid database/cache queries if possible, but support larger messages that don't fit in a cookie (> 4kb) when needed
  • Don't lose messages if they're not displayed to the user (lazy message loading)
  • Sign cookie-based messages
  • Avoid pickling because of the obvious security concerns
  • Provide a standard, intuitive interface so that reusable apps can provide feedback related to the current session
  • Support different "levels" (e.g., info, warning, error, etc.) of messages, with the ability to specify custom levels as needed

Community criteria necessary for inclusion in the core:

  • Needs community approval/support
  • Needs to be the "de facto" standard implementation

Available Options

Name and LinkAnonymous user supportSession FallbackLazy loads messagesSigned cookiesAvoids picklingStandard interfaceMessage Levels
django-notifyyesyesyesyesyesyesyes (via "tags")
[https://github.com/AliLozano/django-messages-extendsyesyesyesyesyesyesyes (same that django.contrib.messages)
django-flashyesnonoyesnonoyes (but not in a standard way)
django-flash-statusyesnonoyesnoyesyes, "errors" or "statuses"
django-cnotesyesnonoyesnoyesno
django-noticesyesnoyes?no (no cookie support)n/ayesyes
  • yes means yes, always or, at least, can be configured to do this
  • no means no, not in the current implementation
  • n/a means not applicable

Please update this table with new options or corrected information as necessary.

Potential App Names

A number of different names have been suggested on the developers thread and elsewhere. Since (a) messages seem to be a commonly understood name for this project, and (b) there's a good chance we'll use the {{ messages }} template variable as the "turning point" between the two APIs, the app should most likely be called 'messages' as well. Here are some of the other ideas that have been discussed:

  • notifications
  • notices
  • alerts
  • notes

Potential API

The API is under heavy discussion on the django-developers list. Following is a representation of what it might look like:

from django.contrib import messages

messages.add_message(request, messages.INFO, 'message')
# or
messages.error(request, 'message')

Using messages in your template

{% if messages %}
<ul>
    {% for message in messages %}
    <li{% if message.level %} class="{{ message.level }}"{% endif %}>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

Note that this is exactly the same as the existing API, with the optional addition of message.level in the LI's class attribute.

Pre-configured Message Levels

Custom message levels may be easily configured for any type of message that does not fit into the pre-set levels, or where more granularity is needed. Consistency is needed regarding what a given level of message means, because multiple, independent Django apps may be combined to form a single project, and consistency is desired in the display of user feedback. It is recommended that reusable apps do not use custom message levels, if possible.

  • DEBUG: Development-related messages that will be removed before a production deployment
  • INFO: Informational messages for the user
  • SUCCESS: An action was successful, e.g. "Your profile was updated successfully"
  • WARNING: A failure did not occur but may be imminent
  • ERROR: An action was not successful or some other failure occurred

TODO Once a Solution is Chosen

  • Clean up the API, if necessary, to make it the de facto standard implementation for Django
  • Review the code and make any additional feature changes necessary to support the technical criteria necessary for inclusion

Other Considerations

  • This app will ideally take advantage of the cookie signing API that is also proposed for 1.2.