Index: django/core/context_processors.py
===================================================================
--- django/core/context_processors.py	(revision 7053)
+++ django/core/context_processors.py	(working copy)
@@ -8,6 +8,7 @@
 """
 
 from django.conf import settings
+from django.utils.encoding import StrAndUnicode
 
 def auth(request):
     """
@@ -22,12 +23,32 @@
     else:
         from django.contrib.auth.models import AnonymousUser
         user = AnonymousUser()
-    return {
+    context_extras = {
         'user': user,
-        'messages': user.get_and_delete_messages(),
         'perms': PermWrapper(user),
     }
+    # Add authentication (and session) LazyMessages to the context too.
+    context_extras.update(messages(request))
+    return context_extras
 
+def messages(request):
+    """
+    Returns messages for the session and the current user.
+
+    Note that this processor is only useful to use explicity if you are not
+    using the (enabled by default) auth processor, as it also provides the
+    messages (by calling this method).
+
+    The messages are lazy loaded, so no messages are retreived and deleted
+    unless requested from the template.
+
+    Both contrib.session and contrib.auth are optional. If neither is provided,
+    no 'messages' variable will be added to the context.
+    """
+    if hasattr(request, 'session') or hasattr(request, 'user'):
+        return {'messages': LazyMessages(request)}
+    return {}
+
 def debug(request):
     "Returns context variables helpful for debugging."
     context_extras = {}
@@ -82,3 +103,42 @@
 
     def __getitem__(self, module_name):
         return PermLookupDict(self.user, module_name)
+
+# LazyMessages is used by the `messages` and `auth` context processors.
+
+class LazyMessages(StrAndUnicode):
+    """
+    A lazy proxy for session and authentication messages.
+    """
+    def __init__(self, request):
+        self.request = request
+
+    def __iter__(self):
+        return iter(self.messages)
+
+    def __len__(self):
+        return len(self.messages)
+
+    def __nonzero__(self):
+        return bool(self.messages)
+
+    def __unicode__(self):
+        return unicode(self.messages)
+
+    def __getitem__(self, *args, **kwargs):
+        return self.messages.__getitem__(*args, **kwargs)
+
+    def _get_messages(self):
+        if hasattr(self, '_messages'):
+            return self._messages
+        # First, retreive any messages for the user.
+        if hasattr(self.request, 'user') and \
+           hasattr(self.request.user, 'get_and_delete_messages'):
+            self._messages = self.request.user.get_and_delete_messages()
+        else:
+            self._messages = []
+        # Next, retrieve any messages for the session.
+        if hasattr(self.request, 'session'):
+            self._messages += self.request.session.get_and_delete_messages()
+        return self._messages
+    messages = property(_get_messages)
Index: django/contrib/sessions/tests.py
===================================================================
--- django/contrib/sessions/tests.py	(revision 7053)
+++ django/contrib/sessions/tests.py	(working copy)
@@ -16,6 +16,19 @@
 'dog'
 >>> db_session.pop('some key', 'does not exist')
 'does not exist'
+>>> db_session.get_messages()
+[]
+>>> db_session.create_message('first post')
+>>> db_session.get_messages()
+['first post']
+>>> db_session.get_and_delete_messages()
+['first post']
+>>> db_session.get_and_delete_messages()
+[]
+>>> db_session.create_message('hello')
+>>> db_session.create_message('world')
+>>> db_session.get_and_delete_messages()
+['hello', 'world']
 >>> db_session.save()
 >>> db_session.exists(db_session.session_key)
 True
@@ -33,6 +46,19 @@
 'dog'
 >>> file_session.pop('some key', 'does not exist')
 'does not exist'
+>>> file_session.get_messages()
+[]
+>>> file_session.create_message('first post')
+>>> file_session.get_messages()
+['first post']
+>>> file_session.get_and_delete_messages()
+['first post']
+>>> file_session.get_and_delete_messages()
+[]
+>>> file_session.create_message('hello')
+>>> file_session.create_message('world')
+>>> file_session.get_and_delete_messages()
+['hello', 'world']
 >>> file_session.save()
 >>> file_session.exists(file_session.session_key)
 True
@@ -57,6 +83,19 @@
 'dog'
 >>> cache_session.pop('some key', 'does not exist')
 'does not exist'
+>>> cache_session.get_messages()
+[]
+>>> cache_session.create_message('first post')
+>>> cache_session.get_messages()
+['first post']
+>>> cache_session.get_and_delete_messages()
+['first post']
+>>> cache_session.get_and_delete_messages()
+[]
+>>> cache_session.create_message('hello')
+>>> cache_session.create_message('world')
+>>> cache_session.get_and_delete_messages()
+['hello', 'world']
 >>> cache_session.save()
 >>> cache_session.delete(cache_session.session_key)
 >>> cache_session.exists(cache_session.session_key)
Index: django/contrib/sessions/backends/base.py
===================================================================
--- django/contrib/sessions/backends/base.py	(revision 7053)
+++ django/contrib/sessions/backends/base.py	(working copy)
@@ -18,6 +18,7 @@
     """
     TEST_COOKIE_NAME = 'testcookie'
     TEST_COOKIE_VALUE = 'worked'
+    MESSAGES_NAME = '_messages'
 
     def __init__(self, session_key=None):
         self._session_key = session_key
@@ -68,6 +69,20 @@
     def delete_test_cookie(self):
         del self[self.TEST_COOKIE_NAME]
 
+    def get_messages(self):
+            return self.get(self.MESSAGES_NAME, [])
+
+    def get_and_delete_messages(self):
+            return self.pop(self.MESSAGES_NAME, [])
+
+    def create_message(self, message):
+        messages = self.get(self.MESSAGES_NAME)
+        if messages is None:
+            messages = []
+            self[self.MESSAGES_NAME] = messages
+        messages.append(message)
+        self.modified = True
+
     def encode(self, session_dict):
         "Returns the given session dictionary pickled and encoded as a string."
         pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
Index: tests/regressiontests/messages/__init__.py
===================================================================
Index: tests/regressiontests/messages/tests.py
===================================================================
--- tests/regressiontests/messages/tests.py	(revision 0)
+++ tests/regressiontests/messages/tests.py	(revision 0)
@@ -0,0 +1,77 @@
+"""
+>>> from django.core import context_processors
+>>> from django.http import HttpRequest
+
+Set up request with a fake user and session (just enough to test getting and
+deleting messages).
+>>> request = HttpRequest()
+>>> class FakeMessageObj:
+...     def __init__(self, object, messages):
+...         self.messages = messages
+...         self.object = object
+...     def get_and_delete_messages(self):
+...         print 'Getting and deleting any %s messages...' % self.object
+...         m = self.messages
+...         self.messages = []
+...         return m
+>>> request.user = FakeMessageObj('user', ['User message'])
+>>> request.session = FakeMessageObj('session', ['Message 1', 'Second message'])
+
+Run the messages context processor, and pull out the messages context variable.
+>>> context = context_processors.messages(request)
+>>> messages = context['messages']
+
+The messages context variable is a LazyMessages class. The messages haven't
+actually been retreived (and deleted) yet.
+>>> messages.__class__
+<class 'django.core.context_processors.LazyMessages'>
+
+When any of the following methods are called, the messages are retreived from
+the session (and user if contrib.auth is installed) from the LazyMessages
+object to be retreived: __iter__, __len__, __nonzero__, __unicode__,
+__getitem__
+>>> len(messages)
+Getting and deleting any user messages...
+Getting and deleting any session messages...
+3
+
+When messages are retreived, messages are deleted from the session (and user if
+contrib.auth is installed).
+>>> request.user.messages
+[]
+>>> request.session.messages
+[]
+
+The messages are still available to the LazyMessages instance because it caches
+them.
+>>> for message in messages:
+...     print message
+User message
+Message 1
+Second message
+>>> messages[-1]
+'Second message'
+
+Both contrib.sessions and contrib.auth are optional. If neither are provided,
+no 'messages' variable will be added to the context.
+>>> del request.user
+>>> request.session = FakeMessageObj('session', [])
+>>> context = context_processors.messages(request)
+>>> messages = context['messages']
+>>> if messages:
+...     print 'messages found!'
+Getting and deleting any session messages...
+
+>>> del request.session
+>>> request.user = FakeMessageObj('user', [])
+>>> context = context_processors.messages(request)
+>>> messages = context['messages']
+>>> if messages:
+...     print 'messages found!'
+Getting and deleting any user messages...
+
+>>> del request.user
+>>> context = context_processors.messages(request)
+>>> context
+{}
+"""
Index: tests/regressiontests/messages/models.py
===================================================================
Index: docs/sessions.txt
===================================================================
--- docs/sessions.txt	(revision 7053)
+++ docs/sessions.txt	(working copy)
@@ -193,6 +193,39 @@
         request.session.set_test_cookie()
         return render_to_response('foo/login_form.html')
 
+Messages
+========
+
+**New in Django development version**
+
+The session message system provides a simple way to queue messages for all
+(anonymous or authenticated) site visitors. To associate messages with users in
+the user database, use the `authentication message framework`_.
+
+.. _authentication message framework: ../authentication/#messages
+
+Messages are associated with a session, therefore a message only lasts as long
+as a session is valid (see `browser-length sessions vs. persistent sessions`_).
+
+The message system relies on the session middleware and is accessed via
+``request.session``. The API is simple:
+
+    * To create a new message, use
+      ``request.session.create_message(message='message text').``
+
+    * To retreive the messages, use ``request.session.get_messages()``,
+      which returns a list of any messages (strings) in the session's queue.
+
+    * To retrieve and delete messages, use
+      ``request.session.get_and_delete_messages()``, which returns the list of
+      any messages in the session's queue and then deletes the messages from the
+      queue.
+
+The `django.core.context_processors.messages`_ context processor makes both
+session messages and user messages available to templates.
+
+.. _django.core.context_processors.messages: ../templates_python/#django-core-context_processors-messages
+
 Using sessions out of views
 ===========================
 
Index: docs/authentication.txt
===================================================================
--- docs/authentication.txt	(revision 7053)
+++ docs/authentication.txt	(working copy)
@@ -956,8 +956,11 @@
 Messages
 ========
 
-The message system is a lightweight way to queue messages for given users.
+The user message system is a lightweight way to queue messages for given users.
+To send messages to anonymous users, use `session messages`_.
 
+.. _session framework: ../sessions/#messages
+
 A message is associated with a ``User``. There's no concept of expiration or
 timestamps.
 
@@ -983,24 +986,20 @@
             context_instance=RequestContext(request))
 
 When you use ``RequestContext``, the currently logged-in user and his/her
-messages are made available in the `template context`_ as the template variable
-``{{ messages }}``. Here's an example of template code that displays messages::
+messages are made available in the `template context`_ as the ``{{ messages }}``
+template variable.
 
-    {% if messages %}
-    <ul>
-        {% for message in messages %}
-        <li>{{ message }}</li>
-        {% endfor %}
-    </ul>
-    {% endif %}
+**New in Django development version**
 
-Note that ``RequestContext`` calls ``get_and_delete_messages`` behind the
-scenes, so any messages will be deleted even if you don't display them.
+The ``{{ messages }}`` template variable will also contain session messages.
+For more information, see `django.core.context_processors.messages`_.
 
-Finally, note that this messages framework only works with users in the user
-database. To send messages to anonymous users, use the `session framework`_.
+.. _django.core.context_processors.messages: ../templates_python/#django-core-context_processors-messages
 
-.. _session framework: ../sessions/
+Also note that previously, ``RequestContext`` directly called
+``get_and_delete_messages`` behind the scenes, so any messages were deleted even
+if not displayed. Messages are now only deleted if the ``{{ messages }}``
+variable is accessed in a template.
 
 Other authentication sources
 ============================
Index: docs/templates_python.txt
===================================================================
--- docs/templates_python.txt	(revision 7053)
+++ docs/templates_python.txt	(working copy)
@@ -346,20 +346,29 @@
       logged in). See the `user authentication docs`_.
 
     * ``messages`` -- A list of messages (as strings) for the currently
-      logged-in user. Behind the scenes, this calls
-      ``request.user.get_and_delete_messages()`` for every request. That method
-      collects the user's messages and deletes them from the database.
+      logged-in user.
 
-      Note that messages are set with ``user.message_set.create``. See the
-      `message docs`_ for more.
+      **New in Django development version**
 
+      This ``messages`` list now also contains session messages.
+
+      The messages are not retrieved and cleared (using
+      ``get_and_delete_messages``) until the ``messages`` variable is accessed
+      in a template whereas previously, this context processor called
+      ``request.user.get_and_delete_messages()`` behind the scenes for every
+      request.
+
+      See the `authentication message docs`_ or `session message docs`_ for
+      information on creating messages.
+
     * ``perms`` -- An instance of
       ``django.core.context_processors.PermWrapper``, representing the
       permissions that the currently logged-in user has. See the `permissions
       docs`_.
 
 .. _user authentication docs: ../authentication/#users
-.. _message docs: ../authentication/#messages
+.. _authentication message docs: ../authentication/#messages
+.. _session message docs: ../sessions/#messages
 .. _permissions docs: ../authentication/#permissions
 
 django.core.context_processors.debug
@@ -409,6 +418,32 @@
 `HttpRequest object`_. Note that this processor is not enabled by default;
 you'll have to activate it.
 
+django.core.context_processors.messages
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
+``RequestContext`` will contain a variable ``messages``, which is a list of
+messages (as strings) for the current session and the currently logged-in user.
+See the `session messages docs`_ or the `authentication messages docs`_ for more
+information on using messages.
+
+Note that this processor is only useful if you are not using the (enabled by
+default) ``auth`` processor, as it also provides the ``messages`` variable.
+
+The messages are not retrieved and cleared (using ``get_and_delete_messages``)
+until the ``messages`` variable is accessed in a template.
+
+Here's an example of template code that displays messages made available by this
+context processor::
+
+	{% if messages %}
+	<ul>
+	    {% for message in messages %}
+	    <li>{{ message }}</li>
+	    {% endfor %}
+	</ul>
+	{% endif %}
+
 Writing your own context processors
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
