web/lib/django/contrib/messages/storage/base.py
changeset 29 cc9b7e14412b
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
       
     1 from django.conf import settings
       
     2 from django.utils.encoding import force_unicode, StrAndUnicode
       
     3 from django.contrib.messages import constants, utils
       
     4 
       
     5 
       
     6 LEVEL_TAGS = utils.get_level_tags()
       
     7 
       
     8 
       
     9 class Message(StrAndUnicode):
       
    10     """
       
    11     Represents an actual message that can be stored in any of the supported
       
    12     storage classes (typically session- or cookie-based) and rendered in a view
       
    13     or template.
       
    14     """
       
    15 
       
    16     def __init__(self, level, message, extra_tags=None):
       
    17         self.level = int(level)
       
    18         self.message = message
       
    19         self.extra_tags = extra_tags
       
    20 
       
    21     def _prepare(self):
       
    22         """
       
    23         Prepares the message for serialization by forcing the ``message``
       
    24         and ``extra_tags`` to unicode in case they are lazy translations.
       
    25 
       
    26         Known "safe" types (None, int, etc.) are not converted (see Django's
       
    27         ``force_unicode`` implementation for details).
       
    28         """
       
    29         self.message = force_unicode(self.message, strings_only=True)
       
    30         self.extra_tags = force_unicode(self.extra_tags, strings_only=True)
       
    31 
       
    32     def __eq__(self, other):
       
    33         return isinstance(other, Message) and self.level == other.level and \
       
    34                                               self.message == other.message
       
    35 
       
    36     def __unicode__(self):
       
    37         return force_unicode(self.message)
       
    38 
       
    39     def _get_tags(self):
       
    40         label_tag = force_unicode(LEVEL_TAGS.get(self.level, ''),
       
    41                                   strings_only=True)
       
    42         extra_tags = force_unicode(self.extra_tags, strings_only=True)
       
    43         if extra_tags and label_tag:
       
    44             return u' '.join([extra_tags, label_tag])
       
    45         elif extra_tags:
       
    46             return extra_tags
       
    47         elif label_tag:
       
    48             return label_tag
       
    49         return ''
       
    50     tags = property(_get_tags)
       
    51 
       
    52 
       
    53 class BaseStorage(object):
       
    54     """
       
    55     This is the base backend for temporary message storage.
       
    56 
       
    57     This is not a complete class; to be a usable storage backend, it must be
       
    58     subclassed and the two methods ``_get`` and ``_store`` overridden.
       
    59     """
       
    60 
       
    61     def __init__(self, request, *args, **kwargs):
       
    62         self.request = request
       
    63         self._queued_messages = []
       
    64         self.used = False
       
    65         self.added_new = False
       
    66         super(BaseStorage, self).__init__(*args, **kwargs)
       
    67 
       
    68     def __len__(self):
       
    69         return len(self._loaded_messages) + len(self._queued_messages)
       
    70 
       
    71     def __iter__(self):
       
    72         self.used = True
       
    73         if self._queued_messages:
       
    74             self._loaded_messages.extend(self._queued_messages)
       
    75             self._queued_messages = []
       
    76         return iter(self._loaded_messages)
       
    77 
       
    78     def __contains__(self, item):
       
    79         return item in self._loaded_messages or item in self._queued_messages
       
    80 
       
    81     @property
       
    82     def _loaded_messages(self):
       
    83         """
       
    84         Returns a list of loaded messages, retrieving them first if they have
       
    85         not been loaded yet.
       
    86         """
       
    87         if not hasattr(self, '_loaded_data'):
       
    88             messages, all_retrieved = self._get()
       
    89             self._loaded_data = messages or []
       
    90         return self._loaded_data
       
    91 
       
    92     def _get(self, *args, **kwargs):
       
    93         """
       
    94         Retrieves a list of stored messages. Returns a tuple of the messages
       
    95         and a flag indicating whether or not all the messages originally
       
    96         intended to be stored in this storage were, in fact, stored and
       
    97         retrieved; e.g., ``(messages, all_retrieved)``.
       
    98 
       
    99         **This method must be implemented by a subclass.**
       
   100 
       
   101         If it is possible to tell if the backend was not used (as opposed to
       
   102         just containing no messages) then ``None`` should be returned in
       
   103         place of ``messages``.
       
   104         """
       
   105         raise NotImplementedError()
       
   106 
       
   107     def _store(self, messages, response, *args, **kwargs):
       
   108         """
       
   109         Stores a list of messages, returning a list of any messages which could
       
   110         not be stored.
       
   111 
       
   112         One type of object must be able to be stored, ``Message``.
       
   113 
       
   114         **This method must be implemented by a subclass.**
       
   115         """
       
   116         raise NotImplementedError()
       
   117 
       
   118     def _prepare_messages(self, messages):
       
   119         """
       
   120         Prepares a list of messages for storage.
       
   121         """
       
   122         for message in messages:
       
   123             message._prepare()
       
   124 
       
   125     def update(self, response):
       
   126         """
       
   127         Stores all unread messages.
       
   128 
       
   129         If the backend has yet to be iterated, previously stored messages will
       
   130         be stored again. Otherwise, only messages added after the last
       
   131         iteration will be stored.
       
   132         """
       
   133         self._prepare_messages(self._queued_messages)
       
   134         if self.used:
       
   135             return self._store(self._queued_messages, response)
       
   136         elif self.added_new:
       
   137             messages = self._loaded_messages + self._queued_messages
       
   138             return self._store(messages, response)
       
   139 
       
   140     def add(self, level, message, extra_tags=''):
       
   141         """
       
   142         Queues a message to be stored.
       
   143 
       
   144         The message is only queued if it contained something and its level is
       
   145         not less than the recording level (``self.level``).
       
   146         """
       
   147         if not message:
       
   148             return
       
   149         # Check that the message level is not less than the recording level.
       
   150         level = int(level)
       
   151         if level < self.level:
       
   152             return
       
   153         # Add the message.
       
   154         self.added_new = True
       
   155         message = Message(level, message, extra_tags=extra_tags)
       
   156         self._queued_messages.append(message)
       
   157 
       
   158     def _get_level(self):
       
   159         """
       
   160         Returns the minimum recorded level.
       
   161 
       
   162         The default level is the ``MESSAGE_LEVEL`` setting. If this is
       
   163         not found, the ``INFO`` level is used.
       
   164         """
       
   165         if not hasattr(self, '_level'):
       
   166             self._level = getattr(settings, 'MESSAGE_LEVEL', constants.INFO)
       
   167         return self._level
       
   168 
       
   169     def _set_level(self, value=None):
       
   170         """
       
   171         Sets a custom minimum recorded level.
       
   172 
       
   173         If set to ``None``, the default level will be used (see the
       
   174         ``_get_level`` method).
       
   175         """
       
   176         if value is None and hasattr(self, '_level'):
       
   177             del self._level
       
   178         else:
       
   179             self._level = int(value)
       
   180 
       
   181     level = property(_get_level, _set_level, _set_level)