Skip to content

Instantly share code, notes, and snippets.

@gearheart
Created June 25, 2011 19:15
Show Gist options
  • Save gearheart/1046793 to your computer and use it in GitHub Desktop.
Save gearheart/1046793 to your computer and use it in GitHub Desktop.
Django view-tags with one function
'''
This module introduces viewtag concept:
funcions that act both as template tags and as views.
Example usage:
First in urls (once):
url(r'^viewtag/([-\w]+)/$', 'viewtags.view', name='viewtag'),
and
viewtags.autodiscover()
Then in app/viewtags.py:
from placeforpeople.viewtags import viewtag, model_arg
@viewtag('viewtag_test.html', [model_arg('obj', Object)]) # you can use querysets too
def test_viewtag(request, obj, page=0):
return {
'obj': obj,
'page': page,
}
Later in templates:
{% vt:test_viewtag campaign %}
or
$.get('{% url viewtag "test_viewtag" %}', {page: 2, object: 5}, function(data) {
$('body').append(data);
});
'''
import inspect
from django import template
from django.template.loader import get_template
from django.http import Http404
from django.shortcuts import render_to_response
from django.utils.importlib import import_module
from django.conf import settings
register = template.Library()
template.builtins.append(register)
_viewtags_registry = {}
def viewtag(template, args=[]):
def decorator(func):
_register_tag(func, template)
_viewtags_registry[func.__name__] = (func, template, args)
return func
return decorator
def view(request, viewtag_name):
try:
func, template_, arg_processors = _viewtags_registry[viewtag_name]
except KeyError:
raise Http404()
argnames = inspect.getargspec(func).args
kwargs = {}
for argname in argnames:
if argname in request.REQUEST and argname != 'request':
kwargs[argname] = request.REQUEST[argname]
for proc in arg_processors:
kwargs = proc(request, kwargs)
return render_to_response(template_, func(request, **kwargs), template.RequestContext(request))
def model_arg(key, qs_or_model):
from django.db import models
if isinstance(qs_or_model, models.base.ModelBase):
qs = qs_or_model._default_manager.all()
else:
qs = qs_or_model
def processor(request, kwargs):
id = request.REQUEST.get(key) or request.REQUEST.get(key + '_id')
if not id is None:
kwargs[key] = qs.get(id=id)
return kwargs
return processor
def autodiscover():
for app in settings.INSTALLED_APPS:
try:
import_module('%s.viewtags' % app)
except ImportError:
pass
def _register_tag(func, template):
def tag(parser, token):
parts = token.split_contents()
args, kwargs = [], []
for part in parts[1:]:
if '=' in part:
kwargs.append(part.split('=', 1))
else:
args.append(part)
return TempNode(func, template, args, dict(kwargs))
register.tag('vt:' + func.__name__, tag)
class TempNode(template.Node):
def __init__(self, func, template_, args, kwargs):
self.func = func
self.template = get_template(template_)
self.args = [template.Variable(arg) for arg in args]
self.kwargs = dict([(k, template.Variable(v)) for (k,v) in kwargs.items()])
def render(self, context):
args = [context['request']] + [arg.resolve(context) for arg in self.args]
kwargs = dict([
(key, val.resolve(context)) for (key, val) in self.kwargs.items()
])
context.update(self.func(*args, **kwargs))
res = self.template.render(context)
context.pop()
return res
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment