Login

Cookie based flash errors and notices (a la Rails)

Author:
alexk
Posted:
September 17, 2008
Language:
Python
Version:
1.0
Tags:
error flash rails notification notice
Score:
4 (after 4 ratings)

This is a light-weight flash implementation. Instead of hitting the database it uses cookies. The messages are shown to the user only once, after that the cookies are deleted.

I tested it on Google App Engine, but it should work on vanilla Django as well, there's no GAE specific code.

To set up, add "path.to.flash.Middleware" to the MIDDLEWARE_CLASSES list.

Also add 'path.to.flash.context_processor' to the TEMPLATE_CONTEXT_PROCESSORS list.

In your views, import and call flash_error(msg) and flash_notice(msg) passing the message that you want to show.

In your base template use this mark up:

{% if flash.notice %}
<div id="flash_notice">
    <p>{{ flash.notice }}</p>
</div>
{% endif %}
{% if flash.error %}
<div id="flash_error">
   <p>{{ flash.error }}</p>
</div>
{% endif %}

And finally, add this to your CSS file changing colours as necessary:

#flash_error {
    margin-top: 30px;
    padding: 20px;
    background-color: #FFCCCC;
    border: solid 1px #CC0000;
}

#flash_notice {
    margin-top: 30px;
    padding: 20px;
    background-color: #CCFFCC;
    border: solid 1px #00CC00;
}

#flash_error p, #flash_notice p {
    margin: 0px;
}

Please comment if you notice any FUs. I'm new to Django and will appreciate any feedback.

 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
from hashlib import sha1
import pickle

import settings

COOKIE_NAME_ERROR = 'flash-error'
COOKIE_NAME_NOTICE = 'flash-notice'

def flash_error(msg):
    Flash.set_error = msg

def flash_notice(msg):
    Flash.set_notice = msg

def context_processor(request):
    if COOKIE_NAME_ERROR in request.COOKIES:
        Flash.error = _decode(request.COOKIES[COOKIE_NAME_ERROR])
    elif Flash.set_error:
        Flash.error, Flash.set_error = Flash.set_error, None
        
    if COOKIE_NAME_NOTICE in request.COOKIES:
        Flash.notice = _decode(request.COOKIES[COOKIE_NAME_NOTICE])
    elif Flash.set_notice:
        Flash.notice, Flash.set_notice = Flash.set_notice, None
    
    return {'flash': Flash}

class Middleware(object):
    
    def process_request(self, request):
        Flash.clear()

    def process_response(self, request, response):
        if Flash.set_error:
            response.set_cookie(COOKIE_NAME_ERROR, _encode(Flash.set_error))
        else:
            response.delete_cookie(COOKIE_NAME_ERROR)
        if Flash.set_notice:
            response.set_cookie(COOKIE_NAME_NOTICE, _encode(Flash.set_notice))
        else:
            response.delete_cookie(COOKIE_NAME_NOTICE)
        
        return response

def _encode(value):
    value = pickle.dumps(value)
    hash = sha1(value + settings.SECRET_KEY)
    return '%s$%s' % (hash.hexdigest(), value)

def _decode(cookie):
    s = cookie.split('$', 1)
    if not s or len(s) != 2:
        return None
    hash, value = s
    if sha1(value + settings.SECRET_KEY).hexdigest() != hash:
        return None
    return pickle.loads(value)
        
class Flash(object):
    @classmethod 
    def clear(cls):
        cls.error = None
        cls.notice = None
        cls.set_error = None
        cls.set_notice = None        

More like this

  1. Templatetag startswith + message tuned by io_error 6 years, 11 months ago
  2. Extended rails flash implementation by miracle2k 7 years, 10 months ago
  3. CSS Preprocessor by jokull 7 years, 8 months ago
  4. Flash Message Template Tag by rtconner 7 years, 10 months ago
  5. Notifications Middleware for Session-Backed Messages by tclineks 6 years, 9 months ago

Comments

alexk (on September 21, 2008):

Thanks guys, I will revamp my code.

#

alexk (on September 24, 2008):

I fixed the code. The cookies are now prefixed with a salted hash value which is checked before unpickling. Thanks again!

#

guettli (on December 5, 2008):

I see two problems:

The class Flash is a global variable, which is shared by all threads. I would prefer to store the messages on the request object.

I would use a list of messages. Something like this:

def flash_error(self, msg):
    self.flash(msg, 'error')

def flash(self, msg, loglevel='notice')
    self.flashes.append((msg, loglevel))

#

Please login first before commenting.