Ticket #4604: messages.7.diff

File messages.7.diff, 15.5 KB (added by Chris Beaven, 17 years ago)

implement __getitem__ too, some people are using stuff like {{ messages.0 }}

  • django/core/context_processors.py

     
    88"""
    99
    1010from django.conf import settings
     11from django.utils.encoding import StrAndUnicode
    1112
    1213def auth(request):
    1314    """
     
    2223    else:
    2324        from django.contrib.auth.models import AnonymousUser
    2425        user = AnonymousUser()
    25     return {
     26    context_extras = {
    2627        'user': user,
    27         'messages': user.get_and_delete_messages(),
    2828        'perms': PermWrapper(user),
    2929    }
     30    # Add authentication (and session) LazyMessages to the context too.
     31    context_extras.update(messages(request))
     32    return context_extras
    3033
     34def messages(request):
     35    """
     36    Returns messages for the session and the current user.
     37
     38    Note that this processor is only useful to use explicity if you are not
     39    using the (enabled by default) auth processor, as it also provides the
     40    messages (by calling this method).
     41
     42    The messages are lazy loaded, so no messages are retreived and deleted
     43    unless requested from the template.
     44
     45    Both contrib.session and contrib.auth are optional. If neither is provided,
     46    no 'messages' variable will be added to the context.
     47    """
     48    if hasattr(request, 'session') or hasattr(request, 'user'):
     49        return {'messages': LazyMessages(request)}
     50    return {}
     51
    3152def debug(request):
    3253    "Returns context variables helpful for debugging."
    3354    context_extras = {}
     
    82103
    83104    def __getitem__(self, module_name):
    84105        return PermLookupDict(self.user, module_name)
     106
     107# LazyMessages is used by the `messages` and `auth` context processors.
     108
     109class LazyMessages(StrAndUnicode):
     110    """
     111    A lazy proxy for session and authentication messages.
     112    """
     113    def __init__(self, request):
     114        self.request = request
     115
     116    def __iter__(self):
     117        return iter(self.messages)
     118
     119    def __len__(self):
     120        return len(self.messages)
     121
     122    def __nonzero__(self):
     123        return bool(self.messages)
     124
     125    def __unicode__(self):
     126        return unicode(self.messages)
     127
     128    def __getitem__(self, *args, **kwargs):
     129        return self.messages.__getitem__(*args, **kwargs)
     130
     131    def _get_messages(self):
     132        if hasattr(self, '_messages'):
     133            return self._messages
     134        # First, retreive any messages for the user.
     135        if hasattr(self.request, 'user') and \
     136           hasattr(self.request.user, 'get_and_delete_messages'):
     137            self._messages = self.request.user.get_and_delete_messages()
     138        else:
     139            self._messages = []
     140        # Next, retrieve any messages for the session.
     141        if hasattr(self.request, 'session'):
     142            self._messages += self.request.session.get_and_delete_messages()
     143        return self._messages
     144    messages = property(_get_messages)
  • django/contrib/sessions/tests.py

     
    1616'dog'
    1717>>> db_session.pop('some key', 'does not exist')
    1818'does not exist'
     19>>> db_session.get_messages()
     20[]
     21>>> db_session.create_message('first post')
     22>>> db_session.get_messages()
     23['first post']
     24>>> db_session.get_and_delete_messages()
     25['first post']
     26>>> db_session.get_and_delete_messages()
     27[]
     28>>> db_session.create_message('hello')
     29>>> db_session.create_message('world')
     30>>> db_session.get_and_delete_messages()
     31['hello', 'world']
    1932>>> db_session.save()
    2033>>> db_session.exists(db_session.session_key)
    2134True
     
    3346'dog'
    3447>>> file_session.pop('some key', 'does not exist')
    3548'does not exist'
     49>>> file_session.get_messages()
     50[]
     51>>> file_session.create_message('first post')
     52>>> file_session.get_messages()
     53['first post']
     54>>> file_session.get_and_delete_messages()
     55['first post']
     56>>> file_session.get_and_delete_messages()
     57[]
     58>>> file_session.create_message('hello')
     59>>> file_session.create_message('world')
     60>>> file_session.get_and_delete_messages()
     61['hello', 'world']
    3662>>> file_session.save()
    3763>>> file_session.exists(file_session.session_key)
    3864True
     
    5783'dog'
    5884>>> cache_session.pop('some key', 'does not exist')
    5985'does not exist'
     86>>> cache_session.get_messages()
     87[]
     88>>> cache_session.create_message('first post')
     89>>> cache_session.get_messages()
     90['first post']
     91>>> cache_session.get_and_delete_messages()
     92['first post']
     93>>> cache_session.get_and_delete_messages()
     94[]
     95>>> cache_session.create_message('hello')
     96>>> cache_session.create_message('world')
     97>>> cache_session.get_and_delete_messages()
     98['hello', 'world']
    6099>>> cache_session.save()
    61100>>> cache_session.delete(cache_session.session_key)
    62101>>> cache_session.exists(cache_session.session_key)
  • django/contrib/sessions/backends/base.py

     
    1818    """
    1919    TEST_COOKIE_NAME = 'testcookie'
    2020    TEST_COOKIE_VALUE = 'worked'
     21    MESSAGES_NAME = '_messages'
    2122
    2223    def __init__(self, session_key=None):
    2324        self._session_key = session_key
     
    6869    def delete_test_cookie(self):
    6970        del self[self.TEST_COOKIE_NAME]
    7071
     72    def get_messages(self):
     73            return self.get(self.MESSAGES_NAME, [])
     74
     75    def get_and_delete_messages(self):
     76            return self.pop(self.MESSAGES_NAME, [])
     77
     78    def create_message(self, message):
     79        messages = self.get(self.MESSAGES_NAME)
     80        if messages is None:
     81            messages = []
     82            self[self.MESSAGES_NAME] = messages
     83        messages.append(message)
     84        self.modified = True
     85
    7186    def encode(self, session_dict):
    7287        "Returns the given session dictionary pickled and encoded as a string."
    7388        pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
  • tests/regressiontests/messages/tests.py

     
     1"""
     2>>> from django.core import context_processors
     3>>> from django.http import HttpRequest
     4
     5Set up request with a fake user and session (just enough to test getting and
     6deleting messages).
     7>>> request = HttpRequest()
     8>>> class FakeMessageObj:
     9...     def __init__(self, object, messages):
     10...         self.messages = messages
     11...         self.object = object
     12...     def get_and_delete_messages(self):
     13...         print 'Getting and deleting any %s messages...' % self.object
     14...         m = self.messages
     15...         self.messages = []
     16...         return m
     17>>> request.user = FakeMessageObj('user', ['User message'])
     18>>> request.session = FakeMessageObj('session', ['Message 1', 'Second message'])
     19
     20Run the messages context processor, and pull out the messages context variable.
     21>>> context = context_processors.messages(request)
     22>>> messages = context['messages']
     23
     24The messages context variable is a LazyMessages class. The messages haven't
     25actually been retreived (and deleted) yet.
     26>>> messages.__class__
     27<class 'django.core.context_processors.LazyMessages'>
     28
     29When any of the following methods are called, the messages are retreived from
     30the session (and user if contrib.auth is installed) from the LazyMessages
     31object to be retreived: __iter__, __len__, __nonzero__, __unicode__,
     32__getitem__
     33>>> len(messages)
     34Getting and deleting any user messages...
     35Getting and deleting any session messages...
     363
     37
     38When messages are retreived, messages are deleted from the session (and user if
     39contrib.auth is installed).
     40>>> request.user.messages
     41[]
     42>>> request.session.messages
     43[]
     44
     45The messages are still available to the LazyMessages instance because it caches
     46them.
     47>>> for message in messages:
     48...     print message
     49User message
     50Message 1
     51Second message
     52>>> messages[-1]
     53'Second message'
     54
     55Both contrib.sessions and contrib.auth are optional. If neither are provided,
     56no 'messages' variable will be added to the context.
     57>>> del request.user
     58>>> request.session = FakeMessageObj('session', [])
     59>>> context = context_processors.messages(request)
     60>>> messages = context['messages']
     61>>> if messages:
     62...     print 'messages found!'
     63Getting and deleting any session messages...
     64
     65>>> del request.session
     66>>> request.user = FakeMessageObj('user', [])
     67>>> context = context_processors.messages(request)
     68>>> messages = context['messages']
     69>>> if messages:
     70...     print 'messages found!'
     71Getting and deleting any user messages...
     72
     73>>> del request.user
     74>>> context = context_processors.messages(request)
     75>>> context
     76{}
     77"""
  • docs/sessions.txt

     
    193193        request.session.set_test_cookie()
    194194        return render_to_response('foo/login_form.html')
    195195
     196Messages
     197========
     198
     199**New in Django development version**
     200
     201The session message system provides a simple way to queue messages for all
     202(anonymous or authenticated) site visitors. To associate messages with users in
     203the user database, use the `authentication message framework`_.
     204
     205.. _authentication message framework: ../authentication/#messages
     206
     207Messages are associated with a session, therefore a message only lasts as long
     208as a session is valid (see `browser-length sessions vs. persistent sessions`_).
     209
     210The message system relies on the session middleware and is accessed via
     211``request.session``. The API is simple:
     212
     213    * To create a new message, use
     214      ``request.session.create_message(message='message text').``
     215
     216    * To retreive the messages, use ``request.session.get_messages()``,
     217      which returns a list of any messages (strings) in the session's queue.
     218
     219    * To retrieve and delete messages, use
     220      ``request.session.get_and_delete_messages()``, which returns the list of
     221      any messages in the session's queue and then deletes the messages from the
     222      queue.
     223
     224The `django.core.context_processors.messages`_ context processor makes both
     225session messages and user messages available to templates.
     226
     227.. _django.core.context_processors.messages: ../templates_python/#django-core-context_processors-messages
     228
    196229Using sessions out of views
    197230===========================
    198231
  • docs/authentication.txt

     
    956956Messages
    957957========
    958958
    959 The message system is a lightweight way to queue messages for given users.
     959The user message system is a lightweight way to queue messages for given users.
     960To send messages to anonymous users, use `session messages`_.
    960961
     962.. _session framework: ../sessions/#messages
     963
    961964A message is associated with a ``User``. There's no concept of expiration or
    962965timestamps.
    963966
     
    983986            context_instance=RequestContext(request))
    984987
    985988When you use ``RequestContext``, the currently logged-in user and his/her
    986 messages are made available in the `template context`_ as the template variable
    987 ``{{ messages }}``. Here's an example of template code that displays messages::
     989messages are made available in the `template context`_ as the ``{{ messages }}``
     990template variable.
    988991
    989     {% if messages %}
    990     <ul>
    991         {% for message in messages %}
    992         <li>{{ message }}</li>
    993         {% endfor %}
    994     </ul>
    995     {% endif %}
     992**New in Django development version**
    996993
    997 Note that ``RequestContext`` calls ``get_and_delete_messages`` behind the
    998 scenes, so any messages will be deleted even if you don't display them.
     994The ``{{ messages }}`` template variable will also contain session messages.
     995For more information, see `django.core.context_processors.messages`_.
    999996
    1000 Finally, note that this messages framework only works with users in the user
    1001 database. To send messages to anonymous users, use the `session framework`_.
     997.. _django.core.context_processors.messages: ../templates_python/#django-core-context_processors-messages
    1002998
    1003 .. _session framework: ../sessions/
     999Also note that previously, ``RequestContext`` directly called
     1000``get_and_delete_messages`` behind the scenes, so any messages were deleted even
     1001if not displayed. Messages are now only deleted if the ``{{ messages }}``
     1002variable is accessed in a template.
    10041003
    10051004Other authentication sources
    10061005============================
  • docs/templates_python.txt

     
    346346      logged in). See the `user authentication docs`_.
    347347
    348348    * ``messages`` -- A list of messages (as strings) for the currently
    349       logged-in user. Behind the scenes, this calls
    350       ``request.user.get_and_delete_messages()`` for every request. That method
    351       collects the user's messages and deletes them from the database.
     349      logged-in user.
    352350
    353       Note that messages are set with ``user.message_set.create``. See the
    354       `message docs`_ for more.
     351      **New in Django development version**
    355352
     353      This ``messages`` list now also contains session messages.
     354
     355      The messages are not retrieved and cleared (using
     356      ``get_and_delete_messages``) until the ``messages`` variable is accessed
     357      in a template whereas previously, this context processor called
     358      ``request.user.get_and_delete_messages()`` behind the scenes for every
     359      request.
     360
     361      See the `authentication message docs`_ or `session message docs`_ for
     362      information on creating messages.
     363
    356364    * ``perms`` -- An instance of
    357365      ``django.core.context_processors.PermWrapper``, representing the
    358366      permissions that the currently logged-in user has. See the `permissions
    359367      docs`_.
    360368
    361369.. _user authentication docs: ../authentication/#users
    362 .. _message docs: ../authentication/#messages
     370.. _authentication message docs: ../authentication/#messages
     371.. _session message docs: ../sessions/#messages
    363372.. _permissions docs: ../authentication/#permissions
    364373
    365374django.core.context_processors.debug
     
    409418`HttpRequest object`_. Note that this processor is not enabled by default;
    410419you'll have to activate it.
    411420
     421django.core.context_processors.messages
     422~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     423
     424If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
     425``RequestContext`` will contain a variable ``messages``, which is a list of
     426messages (as strings) for the current session and the currently logged-in user.
     427See the `session messages docs`_ or the `authentication messages docs`_ for more
     428information on using messages.
     429
     430Note that this processor is only useful if you are not using the (enabled by
     431default) ``auth`` processor, as it also provides the ``messages`` variable.
     432
     433The messages are not retrieved and cleared (using ``get_and_delete_messages``)
     434until the ``messages`` variable is accessed in a template.
     435
     436Here's an example of template code that displays messages made available by this
     437context processor::
     438
     439        {% if messages %}
     440        <ul>
     441            {% for message in messages %}
     442            <li>{{ message }}</li>
     443            {% endfor %}
     444        </ul>
     445        {% endif %}
     446
    412447Writing your own context processors
    413448~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    414449
Back to Top