Skip to content

Instantly share code, notes, and snippets.

@asadawan
Created July 13, 2011 18:18
Show Gist options
  • Save asadawan/1080930 to your computer and use it in GitHub Desktop.
Save asadawan/1080930 to your computer and use it in GitHub Desktop.
A base view handler for djano projects. Gives lots of utils and lets you use classes for handling views. It also extracts query parms from requests to args saving you on lots of if-conditions in the view code.
'''
@author: asad k awan
@copyright: asad k awan
@license: Apache
'''
import re
from django.http import HttpResponse, HttpResponseBadRequest
from django.db.models.query import QuerySet
from django.shortcuts import render_to_response
from django.utils.cache import patch_response_headers
from django.contrib.auth import SESSION_KEY as AUTH_SESSION_KEY
from django.utils import simplejson as json
from django.core.serializers.json import DjangoJSONEncoder
from base.utils import getFromCacheWithGrace, setToCacheWithGrace, PySer, getBaseTemplateDict
import logging
def wrapper(klass,
append_request_method = False,
pull_params_to_args = False,
method = "do", **kwargs):
"""
Generates returns a callable view handler from handler object.
"""
t = (method, append_request_method, pull_params_to_args)
def func(request, **kw):
o = klass(request, **kw)
(method, arm, ppta) = t
if arm:
r = request.method
method = "%s_%s" % (method, r)
if ppta:
d = getattr(request, r)
for (k, v) in d.iterlists():
kw[str("q_%s" % k)] = v #unicode keys not allowed.
f = getattr(o, method, o.do)
try:
return f(**kw)
except TypeError, e:
if unicode(e).startswith(method+'('):
logging.warn(unicode(e))
return HttpResponseBadRequest()
else:
raise
return func
class BaseHandler(object):
'''
All request handlers to be derived from this class.
At the least, override do(**kw) function.
If a different function name is desired, then
set method = xx in the call to wrapper.
For making different handlers for GET, POST, just
set 'append_request_method' in the call to wrapper. This will make
the wrapper call do_GET, do_POST, or xx_GET, ... (if you provided method name).
You can force URL re match to be parameters to your handler function
e.g., def do(self, cust_id, **kw) for re'^/customers/(P?<cust_id>\w+)$
You can also force GET/POST dict to be parameters e.g.,
def do_GET(self, q_query_param1, **kw)
For forcing GET/POST params you must set, in the call to wrapper:
append_request_method = True and pull_params_to_args = True
The GET/POST param variables will have a 'q_' appended to them. So to get a query
parameter f you will need to have 'q_f' as an arg of the function.
In every case, remember to have the **kw args to your handler function.
'''
safeJsonpCbkPattern = re.compile(r'^\w[\.\w]*\w$')
contentType = {'json': 'application/json; charset=utf-8',
'PY': 'py',
'js': 'text/javascript; charset=utf-8',
'html': 'text/html; charset=utf-8' }
_pySer = PySer()
def __init__(self, request, **kw):
self.req = request
self.args = kw
self.logging = logging
self.template = None
self._isAuth = None
self._person = None
self._outFmt = kw.get('format', 'html').lower()
def do(self, **kw):
return self.badRequestResponse('No Impl')
def errorTemplateResponse(self, httpCode=500):
template = '%d.html' % httpCode
resp = render_to_response(template, {"request" : self.req})
resp.status_code = httpCode
return resp
def badRequestResponse(self, d, *a, **kw):
fmt = self._outFmt
kw['content_type'] = self.contentType[fmt]
if fmt == 'json':
d = json.dumps({'err': d}, cls = DjangoJSONEncoder)
return HttpResponseBadRequest(d, *a, **kw)
def response(self, c, *a, **kw):
outFmt = self._outFmt
ctype = self.contentType[self._outFmt]
if ctype == 'py': return c
kw['content_type'] = ctype
if outFmt == 'json':
return self._jsonResponse(c, *a, **kw)
elif self.template:
self.render(self.template, c, *a, **kw)
else: return HttpResponse(c, *a, **kw)
def _jsonResponse(self, data, *a, **kw):
if isinstance(data, QuerySet): data = self._pySer.serialize(data)
cbk = self.req.GET.get('callback')
js = json.dumps(data, cls = DjangoJSONEncoder, separators=(',',':'))
if cbk is not None: # check if jsonp is requested.
kw['content_type'] = self.contentType['js']
if self.safeJsonpCbkPattern.match(cbk):
content = '%s(%s);' %(cbk, js)
else: content = '["bad cbk %s, need chars only"]' % cbk
else: content = js
return HttpResponse(content, *a, **kw)
def getReferer(self):
return self.req.META.get('HTTP_REFERER')
def setCacheHeaders(self, resp, ttl_sec = 0):
"""
Set the cache headers appropriately.
if ttl_sec is zero, it will prevent caching.
"""
patch_response_headers(resp, ttl_sec)
if ttl_sec <= 0: resp['Cache-Control'] = 'no-cache'
def isAuth(self):
### ! NOT FINISHED YET.
if self._isAuth is not None: return self._isAuth
# aim is to try not to load req.user object
ses = self.req.session
ret = ses.has_key(AUTH_SESSION_KEY)
self._isAuth = ret
return ret
def getFromCacheWithGrace(self, key):
return getFromCacheWithGrace(key)
def logDbQuery(self, msg):
from django.db import connection
self.logging.info('%s %s', msg, str(connection.queries))
def setToCacheWithGrace(self, key, value, timeout=86400, graceTime=20):
setToCacheWithGrace(key, value, timeout, graceTime)
def render(self, template_name, dictionary={},
mimetype=contentType['html'], context_instance=None, **kw):
dictionary.update(getBaseTemplateDict(self))
return render_to_response(template_name, dictionary = dictionary, mimetype = mimetype,
context_instance = context_instance, **kw)
def pySer(self, queryset, **kw):
return self._pySer.serialize(queryset, **kw)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment