After using Zope3/Grok for a little, I wondered how hard it would be to implement views as classes in Django, in a similar vain to how it's done in Grok. I came up with something rather simple but effective. It may be more appropriate if you use a template engine other than Django Templates, which allows you to call functions with arguments, but it's still useful none-the-less to encapsulate functions in a class.
You could, for example, extend View to be JinjaView, just replacing render_template().
A nice extension, I imagine, would be to automatically figure out the template name as well as the path prefix for it (since you probably want it to be found under packagename/templatename.html).
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 | from django.template.loader import get_template
from django.template import RequestContext
from django import http
class BaseView(object):
"""
BaseView provides a class that is instantiated and then
called like a function.
__init__ called without arguments.
You must just override the __call__ method.
"""
def __new__(cls, *args, **kwargs):
obj = super(BaseView, cls).__new__(cls)
return obj(*args, **kwargs)
def __call__(self, *args, **kwargs):
pass
class View(BaseView):
"""
View provides a basic django view _class_
It is instantiated for each request, and it is provided to
the template's context as the 'view' varable.
__call__ sets the following:
self.request
self.response
self.context = {}
view.update() is called first. It may do a redirect, additional
checks, or setup information for the template renderer.
If view.render() is defined, it will be run to generate the output.
If its return value is a string (or unicode), self.response.content
will be set to this value. Otherwise its return value will be
returned directly, possibly allowing other Django processors to do
their magic.
If view.render() is not defined, we assume it will be rendered
with a template, so we define a context dictionary, then call
self.render_template.
The context dictionary contains:
'view' : self,
'request' : self.request,
'response' : self.response,
plus anything defined in self.context is merged into the dictionary,
possibly overriding the above variables.
Override render_template(template_name, context_dictionary) to
use an alternate template rendering mechanism.
"""
template = None
context = None
def redirect(self, url):
self.response = http.HttpResponseRedirect(url)
def update(self):
pass
def __call__(self, request, *args, **kwargs):
self.request = request
self.response = http.HttpResponse()
self.update()
if self.response.status_code in (301, 302):
return self.response
if hasattr(self, "render"):
res = self.render()
if isinstance(res, basestring):
self.response.content = res
return self.response
return res
elif self.template:
template = self.template
context = {
'view' : self,
'request' : self.request,
'response' : self.response,
}
extra = getattr(self, 'context', None)
if extra:
context.extend(extra)
r = self.response
r.content = self.render_template(template, context)
return r
else:
if not self.response.content:
self.response.content = 'No Template nor Render Method'
return self.response
def render_template(self, template, context):
"""
Given a template (either a filename to lookup, or an object
with a render() method), lookup the template if necessary, then
wrap the context in a RequestContext and call
template.render(context)
"""
if isinstance(template, basestring):
template = get_template(template)
return template.render(RequestContext(self.request, context))
### example view
class testview(View):
template = "testview.html"
def update(self):
self.age = 29
self.context["nose"] = "normal sized"
self.response["X-Crazy"] = "Maybe"
if self.request.GET.get('next'):
self.redirect(self.request.GET['next'])
def name(self):
return "Robert"
class testview2(View):
template = "testview.html"
def render(self):
return "No template will be used here automatically"
### testview.html:
Hello {{ view.name }}! You are {{ view.age }} years old.
You have a {{ nose }} nose.
|
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, 3 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
Please login first before commenting.