Ticket #4604: t4604-r9698.diff

File t4604-r9698.diff, 14.7 KB (added by Ramiro Morales, 16 years ago)

Patch updated to r9698.

  • django/contrib/sessions/backends/base.py

    diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py
    a b  
    3333    """
    3434    TEST_COOKIE_NAME = 'testcookie'
    3535    TEST_COOKIE_VALUE = 'worked'
     36    MESSAGES_NAME = '_messages'
    3637
    3738    def __init__(self, session_key=None):
    3839        self._session_key = session_key
     
    8283
    8384    def delete_test_cookie(self):
    8485        del self[self.TEST_COOKIE_NAME]
     86
     87    def get_messages(self):
     88            return self.get(self.MESSAGES_NAME, [])
     89
     90    def get_and_delete_messages(self):
     91            return self.pop(self.MESSAGES_NAME, [])
     92
     93    def create_message(self, message):
     94        messages = self.get(self.MESSAGES_NAME)
     95        if messages is None:
     96            messages = []
     97            self[self.MESSAGES_NAME] = messages
     98        messages.append(message)
     99        self.modified = True
    85100
    86101    def encode(self, session_dict):
    87102        "Returns the given session dictionary pickled and encoded as a string."
  • django/contrib/sessions/tests.py

    diff --git a/django/contrib/sessions/tests.py b/django/contrib/sessions/tests.py
    a b  
    1818'dog'
    1919>>> db_session.pop('some key', 'does not exist')
    2020'does not exist'
     21>>> db_session.get_messages()
     22[]
     23>>> db_session.create_message('first post')
     24>>> db_session.get_messages()
     25['first post']
     26>>> db_session.get_and_delete_messages()
     27['first post']
     28>>> db_session.get_and_delete_messages()
     29[]
     30>>> db_session.create_message('hello')
     31>>> db_session.create_message('world')
     32>>> db_session.get_and_delete_messages()
     33['hello', 'world']
    2134>>> db_session.save()
    2235>>> db_session.exists(db_session.session_key)
    2336True
     
    6982'dog'
    7083>>> file_session.pop('some key', 'does not exist')
    7184'does not exist'
     85>>> file_session.get_messages()
     86[]
     87>>> file_session.create_message('first post')
     88>>> file_session.get_messages()
     89['first post']
     90>>> file_session.get_and_delete_messages()
     91['first post']
     92>>> file_session.get_and_delete_messages()
     93[]
     94>>> file_session.create_message('hello')
     95>>> file_session.create_message('world')
     96>>> file_session.get_and_delete_messages()
     97['hello', 'world']
    7298>>> file_session.save()
    7399>>> file_session.exists(file_session.session_key)
    74100True
     
    131157'dog'
    132158>>> cache_session.pop('some key', 'does not exist')
    133159'does not exist'
     160>>> cache_session.get_messages()
     161[]
     162>>> cache_session.create_message('first post')
     163>>> cache_session.get_messages()
     164['first post']
     165>>> cache_session.get_and_delete_messages()
     166['first post']
     167>>> cache_session.get_and_delete_messages()
     168[]
     169>>> cache_session.create_message('hello')
     170>>> cache_session.create_message('world')
     171>>> cache_session.get_and_delete_messages()
     172['hello', 'world']
    134173>>> cache_session.save()
    135174>>> cache_session.delete(cache_session.session_key)
    136175>>> cache_session.exists(cache_session.session_key)
  • django/core/context_processors.py

    diff --git a/django/core/context_processors.py b/django/core/context_processors.py
    a b  
    88"""
    99
    1010from django.conf import settings
     11from django.utils.encoding import StrAndUnicode
     12
     13# LazyMessages is used by the `messages` and `auth` context processors.
     14
     15class LazyMessages(StrAndUnicode):
     16    """
     17    A lazy proxy for session and authentication messages.
     18    """
     19    def __init__(self, request):
     20        self.request = request
     21
     22    def __iter__(self):
     23        return iter(self.messages)
     24
     25    def __len__(self):
     26        return len(self.messages)
     27
     28    def __nonzero__(self):
     29        return bool(self.messages)
     30
     31    def __unicode__(self):
     32        return unicode(self.messages)
     33
     34    def __getitem__(self, *args, **kwargs):
     35        return self.messages.__getitem__(*args, **kwargs)
     36
     37    def _get_messages(self):
     38        if hasattr(self, '_messages'):
     39            return self._messages
     40        # First, retrieve any messages for the user.
     41        if hasattr(self.request, 'user') and \
     42           hasattr(self.request.user, 'get_and_delete_messages'):
     43            self._messages = self.request.user.get_and_delete_messages()
     44        else:
     45            self._messages = []
     46        # Next, retrieve any messages for the session.
     47        if hasattr(self.request, 'session'):
     48            self._messages += self.request.session.get_and_delete_messages()
     49        return self._messages
     50    messages = property(_get_messages)
    1151
    1252def auth(request):
    1353    """
     
    2262    else:
    2363        from django.contrib.auth.models import AnonymousUser
    2464        user = AnonymousUser()
    25     return {
     65    context_extras = {
    2666        'user': user,
    27         'messages': user.get_and_delete_messages(),
    2867        'perms': PermWrapper(user),
    2968    }
     69    # Add authentication (and session) LazyMessages to the context too.
     70    context_extras.update(messages(request))
     71    return context_extras
     72
     73def messages(request):
     74    """
     75    Returns messages for the session and the current user.
     76
     77    Note that this processor is only useful to use explicity if you are not
     78    using the (enabled by default) auth processor, as it also provides the
     79    messages (by calling this method).
     80
     81    The messages are lazy loaded, so no messages are retrieved and deleted
     82    unless requested from the template.
     83
     84    Both contrib.session and contrib.auth are optional. If neither is provided,
     85    no 'messages' variable will be added to the context.
     86    """
     87    if hasattr(request, 'session') or hasattr(request, 'user'):
     88        return {'messages': LazyMessages(request)}
     89    return {}
    3090
    3191def debug(request):
    3292    "Returns context variables helpful for debugging."
  • docs/ref/templates/api.txt

    diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt
    a b  
    352352      logged in).
    353353
    354354    * ``messages`` -- A list of messages (as strings) for the currently
    355       logged-in user. Behind the scenes, this calls
    356       ``request.user.get_and_delete_messages()`` for every request. That method
    357       collects the user's messages and deletes them from the database.
     355      logged-in user.
    358356
    359       Note that messages are set with ``user.message_set.create``.
     357      .. versionadded:: 1.1
     358
     359      This ``messages`` list now also contains session messages.
     360
     361      The messages are not retrieved and cleared (using
     362      ``get_and_delete_messages``) until the ``messages`` variable is accessed
     363      in a template whereas previously, this context processor called
     364      ``request.user.get_and_delete_messages()`` behind the scenes for every
     365      request.
     366
     367      See the :ref:`authentication messages docs<auth-messages>` or
     368      :ref:`session messages docs<sess-messages>` for information on creating
     369      messages.
    360370
    361371    * ``perms`` -- An instance of
    362372      ``django.core.context_processors.PermWrapper``, representing the
     
    404414``RequestContext`` will contain a variable ``request``, which is the current
    405415:class:`~django.http.HttpRequest`. Note that this processor is not enabled by default;
    406416you'll have to activate it.
     417
     418.. _messages-context-processor:
     419
     420django.core.context_processors.messages
     421~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     422
     423If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every
     424``RequestContext`` will contain a variable ``messages``, which is a list of
     425messages (as strings) for the current session and the currently logged-in user.
     426See the :ref:`session messages docs<sess-messages>` or the
     427:ref:`authentication messages docs<auth-messages>` for more information on
     428using 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.. code-block:: html+django
     440
     441    {% if messages %}
     442        <ul>
     443            {% for message in messages %}
     444            <li>{{ message }}</li>
     445            {% endfor %}
     446        </ul>
     447    {% endif %}
    407448
    408449Writing your own context processors
    409450~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • docs/topics/auth.txt

    diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt
    a b  
    11511151access to a members-only portion of your site, or send them members-only e-mail
    11521152messages.
    11531153
     1154.. _auth-messages:
     1155
    11541156Messages
    11551157========
    11561158
    1157 The message system is a lightweight way to queue messages for given users.
     1159The user message system is a lightweight way to queue messages for given users.
     1160To send messages to anonymous users, use :ref:`session messages<sess-messages>`.
    11581161
    11591162A message is associated with a :class:`~django.contrib.auth.models.User`.
    11601163There's no concept of expiration or timestamps.
     
    11861189
    11871190When you use :class:`~django.template.context.RequestContext`, the currently
    11881191logged-in user and his/her messages are made available in the
    1189 :ref:`template context <ref-templates-api>` as the template variable
    1190 ``{{ messages }}``. Here's an example of template code that displays messages::
     1192:ref:`template context <ref-templates-api>` as the ``{{ messages }}`` template
     1193variable.
    11911194
    1192     {% if messages %}
    1193     <ul>
    1194         {% for message in messages %}
    1195         <li>{{ message }}</li>
    1196         {% endfor %}
    1197     </ul>
    1198     {% endif %}
     1195.. versionadded:: 1.1
    11991196
    1200 Note that :class:`~django.template.context.RequestContext` calls
    1201 :meth:`~django.contrib.auth.models.User.get_and_delete_messages` behind the
    1202 scenes, so any messages will be deleted even if you don't display them.
     1197The ``{{ messages }}`` template variable will also contain session messages.
     1198For more information, see :ref:`messages-context-processor`
    12031199
    1204 Finally, note that this messages framework only works with users in the user
    1205 database. To send messages to anonymous users, use the
    1206 :ref:`session framework <topics-http-sessions>`.
     1200Also note that previously, ``RequestContext`` directly called
     1201``get_and_delete_messages`` behind the scenes, so any messages were deleted even
     1202if not displayed. Messages are now only deleted if the ``{{ messages }}``
     1203variable is accessed in a template.
    12071204
    12081205.. _authentication-backends:
    12091206
  • docs/topics/http/sessions.txt

    diff --git a/docs/topics/http/sessions.txt b/docs/topics/http/sessions.txt
    a b  
    266266        request.session.set_test_cookie()
    267267        return render_to_response('foo/login_form.html')
    268268
     269.. _sess-messages:
     270
     271Messages
     272========
     273
     274.. versionadded:: 1.1
     275
     276The session message system provides a simple way to queue messages for all
     277(anonymous or authenticated) site visitors. To associate messages with users in
     278the user database, use the :ref:`authentication message framework<auth-messages>`.
     279
     280Messages are associated with a session, therefore a message only lasts as long
     281as a session is valid (see `browser-length sessions vs. persistent sessions`_).
     282
     283The message system relies on the session middleware and is accessed via
     284``request.session``. The API is simple:
     285
     286    * To create a new message, use
     287      ``request.session.create_message(message='message text').``
     288
     289    * To retrieve the messages, use ``request.session.get_messages()``,
     290      which returns a list of any messages (strings) in the session's queue.
     291
     292    * To retrieve and delete messages, use
     293      ``request.session.get_and_delete_messages()``, which returns the list of
     294      any messages in the session's queue and then deletes the messages from the
     295      queue.
     296
     297The :ref:`messages-context-processor` context processor makes both session
     298messages and user messages available to templates.
     299
    269300Using sessions out of views
    270301===========================
    271302
  • new file tests/regressiontests/messages/__init__.py

    diff --git a/tests/regressiontests/messages/__init__.py b/tests/regressiontests/messages/__init__.py
    new file mode 100644
    - +  
     1
  • new file tests/regressiontests/messages/tests.py

    diff --git a/tests/regressiontests/messages/models.py b/tests/regressiontests/messages/models.py
    new file mode 100644
    diff --git a/tests/regressiontests/messages/tests.py b/tests/regressiontests/messages/tests.py
    new file mode 100644
    - +  
     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"""
Back to Top