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
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Thanks guys, I will revamp my code.
#
I fixed the code. The cookies are now prefixed with a salted hash value which is checked before unpickling. Thanks again!
#
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:
#
Please login first before commenting.