diff options
Diffstat (limited to 'lib/python2.7/site-packages/django/contrib/messages/storage/base.py')
-rw-r--r-- | lib/python2.7/site-packages/django/contrib/messages/storage/base.py | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/django/contrib/messages/storage/base.py b/lib/python2.7/site-packages/django/contrib/messages/storage/base.py new file mode 100644 index 0000000..7fe8a07 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/messages/storage/base.py @@ -0,0 +1,184 @@ +from __future__ import unicode_literals + +from django.conf import settings +from django.utils.encoding import force_text, python_2_unicode_compatible +from django.contrib.messages import constants, utils + + +LEVEL_TAGS = utils.get_level_tags() + + +@python_2_unicode_compatible +class Message(object): + """ + Represents an actual message that can be stored in any of the supported + storage classes (typically session- or cookie-based) and rendered in a view + or template. + """ + + def __init__(self, level, message, extra_tags=None): + self.level = int(level) + self.message = message + self.extra_tags = extra_tags + + def _prepare(self): + """ + Prepares the message for serialization by forcing the ``message`` + and ``extra_tags`` to unicode in case they are lazy translations. + + Known "safe" types (None, int, etc.) are not converted (see Django's + ``force_text`` implementation for details). + """ + self.message = force_text(self.message, strings_only=True) + self.extra_tags = force_text(self.extra_tags, strings_only=True) + + def __eq__(self, other): + return isinstance(other, Message) and self.level == other.level and \ + self.message == other.message + + def __str__(self): + return force_text(self.message) + + def _get_tags(self): + label_tag = force_text(LEVEL_TAGS.get(self.level, ''), + strings_only=True) + extra_tags = force_text(self.extra_tags, strings_only=True) + if extra_tags and label_tag: + return ' '.join([extra_tags, label_tag]) + elif extra_tags: + return extra_tags + elif label_tag: + return label_tag + return '' + tags = property(_get_tags) + + +class BaseStorage(object): + """ + This is the base backend for temporary message storage. + + This is not a complete class; to be a usable storage backend, it must be + subclassed and the two methods ``_get`` and ``_store`` overridden. + """ + + def __init__(self, request, *args, **kwargs): + self.request = request + self._queued_messages = [] + self.used = False + self.added_new = False + super(BaseStorage, self).__init__(*args, **kwargs) + + def __len__(self): + return len(self._loaded_messages) + len(self._queued_messages) + + def __iter__(self): + self.used = True + if self._queued_messages: + self._loaded_messages.extend(self._queued_messages) + self._queued_messages = [] + return iter(self._loaded_messages) + + def __contains__(self, item): + return item in self._loaded_messages or item in self._queued_messages + + @property + def _loaded_messages(self): + """ + Returns a list of loaded messages, retrieving them first if they have + not been loaded yet. + """ + if not hasattr(self, '_loaded_data'): + messages, all_retrieved = self._get() + self._loaded_data = messages or [] + return self._loaded_data + + def _get(self, *args, **kwargs): + """ + Retrieves a list of stored messages. Returns a tuple of the messages + and a flag indicating whether or not all the messages originally + intended to be stored in this storage were, in fact, stored and + retrieved; e.g., ``(messages, all_retrieved)``. + + **This method must be implemented by a subclass.** + + If it is possible to tell if the backend was not used (as opposed to + just containing no messages) then ``None`` should be returned in + place of ``messages``. + """ + raise NotImplementedError() + + def _store(self, messages, response, *args, **kwargs): + """ + Stores a list of messages, returning a list of any messages which could + not be stored. + + One type of object must be able to be stored, ``Message``. + + **This method must be implemented by a subclass.** + """ + raise NotImplementedError() + + def _prepare_messages(self, messages): + """ + Prepares a list of messages for storage. + """ + for message in messages: + message._prepare() + + def update(self, response): + """ + Stores all unread messages. + + If the backend has yet to be iterated, previously stored messages will + be stored again. Otherwise, only messages added after the last + iteration will be stored. + """ + self._prepare_messages(self._queued_messages) + if self.used: + return self._store(self._queued_messages, response) + elif self.added_new: + messages = self._loaded_messages + self._queued_messages + return self._store(messages, response) + + def add(self, level, message, extra_tags=''): + """ + Queues a message to be stored. + + The message is only queued if it contained something and its level is + not less than the recording level (``self.level``). + """ + if not message: + return + # Check that the message level is not less than the recording level. + level = int(level) + if level < self.level: + return + # Add the message. + self.added_new = True + message = Message(level, message, extra_tags=extra_tags) + self._queued_messages.append(message) + + def _get_level(self): + """ + Returns the minimum recorded level. + + The default level is the ``MESSAGE_LEVEL`` setting. If this is + not found, the ``INFO`` level is used. + """ + if not hasattr(self, '_level'): + self._level = getattr(settings, 'MESSAGE_LEVEL', constants.INFO) + return self._level + + def _set_level(self, value=None): + """ + Sets a custom minimum recorded level. + + If set to ``None``, the default level will be used (see the + ``_get_level`` method). + """ + if value is None and hasattr(self, '_level'): + del self._level + else: + self._level = int(value) + + level = property(_get_level, _set_level, _set_level) |