Login

Cookie based Messages (deprecated)

Author:
guettli
Posted:
April 22, 2009
Language:
Python
Version:
1.1
Score:
0 (after 0 ratings)

DEPRECATED: Django has cookie based messages since version 1.2

This messages stores messages for the user in a cookie. I prefer this to session based messages, because the session column is a hot spot in the database if one user works with several browser tabs/windows.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# DEPRECATED: Django has cookie based messages since version 1.2
#
# -*- coding: iso-8859-1 -*-
# $Id: sessionutils.py 322 2009-04-22 10:53:04Z tguettler $
# $HeadURL: svn+ssh://svnserver/svn/djangotools/trunk/utils/sessionutils.py $

u'''

http://www.djangosnippets.org/snippets/1459/

Modify the Session class of django. Create some extra methods.
This way of hacking django is easier than running a modified version.

MessageCookieMiddleware Usage:

def view(request):
    if request.method=='POST':
        ....
        request.session.create_message(u'Your changes have been saved.')
        return django.http.ResponseRedirect(...)

In the code or template where you create your HTML head, you need to insert:
    request.session.get_and_delete_messages()
'''

# Python
import os
import sys
import random
from hashlib import sha1
import pickle

# Django
from django.utils.html import mark_safe
from django.utils.html import conditional_escape as escape
from django.utils.encoding import StrAndUnicode

# Project
from django.conf import settings

KNOWN_LOGLEVELS=['info', 'error']
COOKIE_NAME='%s_messages' % (settings.SESSION_COOKIE_NAME)

class MessageCookieMiddleware(object):
    def process_request(self, request):
        session=getattr(request, 'session', None)
        if session is None:
            return
        cookie=request.COOKIES.get(COOKIE_NAME)
        if cookie:
            session._messages=decode(cookie)
        else:
            session._messages=Messages()
        session._messages_modified=False

    def process_response(self, request, response):
        session=getattr(request, 'session', None)
        if session is None:
            return response
        messages=getattr(session, '_messages', None)
        if messages is None:
            return response
        if not session._messages_modified:
            return response
        if not messages:
            response.delete_cookie(COOKIE_NAME)
        else:
            response.set_cookie(COOKIE_NAME, encode(messages))
        return response

def get_messages(self):
    u'Normaly not needed. Use get_and_delete_messages()'
    messages=getattr(self, '_messages', None)
    if messages is None:
        raise AttributeError('session has no attribute _messages. MessageCookieMiddleware in settings.MIDDLEWARE_CLASSES?')
    return messages

def get_and_delete_messages(self):
    messages=self.get_messages()
    if messages:
        messages=Messages(messages) # copy
        self._messages=Messages()
        self._messages_modified=True
    return messages

class Messages(list, StrAndUnicode):
    def __unicode__(self):
        if not self:
            return u''
        return mark_safe(u'<ul class="messages">%s</ul>' % u''.join([unicode(m) for m in self]))
    def __repr__(self):
        return '<%s object %s messages: %s>' % (self.__class__.__name__, len(self),
                                                u'; '.join([m.message for m in self]))
class Message(object):
    def __init__(self, message, loglevel='info'):
        self.message=message
        assert loglevel in KNOWN_LOGLEVELS, loglevel
        self.loglevel=loglevel
    def __unicode__(self):
        return mark_safe(u'<li class="message-%s">%s</li>' % (self.loglevel, escape(self.message)))

def create_message(self, message, loglevel='info'):
    messages=self.get_messages()
    messages.append(Message(message, loglevel)) 
    self._messages_modified = True


# encode and decode based on from http://www.djangosnippets.org/snippets/1064/
def encode(value):
    assert value
    value = pickle.dumps(value)
    hash = sha1(value + settings.SECRET_KEY)
    return '%s$%s' % (hash.hexdigest(), value)

def decode(cookie):
    u'''
    unpickling of untrusted data is dangerous. Uses settings.SECRET_KEY to
    create a sha1 signature.
    '''
    assert cookie
    s = cookie.split('$', 1)
    hash, value = s
    should = sha1(value + settings.SECRET_KEY).hexdigest() 
    if should != hash:
        raise Exception('verify of sha1 signed cookie failed. should!=hash (%s!=%s)' % (
                should, hash))
    return pickle.loads(value) 

def get_dir(self):
    session_dir=os.path.join(settings.MEDIA_ROOT, 'sessions', self.session_key)
    if not os.path.exists(session_dir):
        os.mkdir(session_dir)
    return session_dir

def get_tempfile(self, extension='', basename=None):
    u'''
    extensions: txt, png, pdf, ...
    '''
    if not basename:
        if extension:
            dot='.'
        else:
            dot=''
        basename='%s%s%s' % (random.randint(0, sys.maxint), dot, extension)
    path=os.path.join(self.get_dir(), basename)
    url='%ssessions/%s/%s' % (settings.MEDIA_URL, self.session_key, basename)
    return (path, url)


# Start Hacking Django
from django.contrib.sessions.backends.base import SessionBase
SessionBase.get_messages=get_messages
SessionBase.get_and_delete_messages=get_and_delete_messages
SessionBase.create_message=create_message
SessionBase.get_dir=get_dir
SessionBase.get_tempfile=get_tempfile
# End Hacking Django

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

guettli (on November 19, 2010):

With Django 1.2 this snippet is deprecated, since django has a message framework with cookie support now.

#

Please login first before commenting.