One of Python's (2.5+) most useful shorthands is the concept of decorators. Here is an example of using Decorators with Django to make view functions a little more "DRY". I probably found the original version of this on
www.djangosnippets.org, but I've made a couple of little "enhancements". First of all, the decorator takes two argument, the first the main template to render, but the second optional argument is the name of the template to render in logged-in mode. This is a useful pattern if the same view has two different templates depending on whether the user is logged-in or not. I've also added an automatic "body_class" context variable to the rendered template that can be used to specify a custom class for the HTML body:
<body class="{{ body_class }}”>
This might not be the cleanest way to do things, but I find it very useful to automatically have a CSS class added to my body tag. Here is how you apply it in your views:
@render_with('mytemplates/template.html')
def my_view(request):
return {'context_var': value}
def render_with(template, logged_in_template=None):
"""
Decorator for Django views that sends returned dict to render_to_response function
with given template and RequestContext as context instance.
"""
def renderer(func):
def wrapper(request, *args, **kw):
template_to_render = logged_in_template if logged_in_template and \
request.user.is_authenticated() else template
output = func(request, *args, **kw)
if request.META['PATH_INFO'] == '/':
body_class = 'home'
else:
body_class = ' '.join('body-'+slugify(p) for p in request.META['PATH_INFO'].split('/') if p)
if isinstance(output, dict):
if 'body_class' not in output:
output.update({'body_class': body_class})
return render_to_response(
template_to_render, output,
CustomRequestContext(request, output)
)
return output
return wrapper
return renderer
2 comments: