- Author:
- jeffschenck
- Posted:
- September 27, 2009
- Language:
- Python
- Version:
- 1.1
- Score:
- 7 (after 7 ratings)
This template tag provides an easy way to render objects in your template, even if you don't know ahead of time what type they are.
For example, if you've got a search page with a result list comprised of objects from various models, you can simply loop through them and render them using the tag. The tag will choose the best template and render the object for you.
The tag's docstring has all the details. I hope you find this as useful as I have. Questions, comments, complaints welcome.
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 | from django import template
from django.template.loader import render_to_string
from django.db.models import Model
from django.utils.safestring import mark_safe
register = template.Library()
BASE_PATH = 'render'
class RenderObjectNode(template.Node):
def __init__(self, object_ref, position, varname):
self.object_ref = template.Variable(object_ref)
if position and position[0] in ('\'', '\"') and position[0] == position[-1]:
position = position[1:-1]
self.position = position
self.varname = varname
def render(self, context):
# Retrieve the object from the template context
try:
object_ref = self.object_ref.resolve(context)
assert isinstance(object_ref, Model)
except (template.VariableDoesNotExist, AssertionError):
# No context variable found, or variable was not a model
model_name = None
else:
model_name = object_ref._meta.app_label + '_' + object_ref._meta.module_name
# Construct the template loader list
templates = []
if self.position:
if model_name:
templates += ['%s/%s/%s.html' % (BASE_PATH, self.position, model_name)]
templates += ['%s/%s/default.html' % (BASE_PATH, self.position)]
if model_name:
templates += ['%s/%s.html' % (BASE_PATH, model_name)]
templates += ['%s/default.html' % BASE_PATH]
# Render the object and output it or add it to the template context
try:
rendered = render_to_string(templates, {'object': object_ref}, context)
except template.TemplateDoesNotExist:
# No template found -- fail silently
if self.varname:
context[self.varname] = ''
return ''
rendered = mark_safe(rendered)
if self.varname:
context[self.varname] = rendered
return ''
else:
return rendered
def do_render_object(parser, token):
"""
Used to output a rendered representation of a given model object.
This tag allows you to use standard templates to describe how you want a given
model to be displayed. Once you have created a rendering template for a model,
you can simply feed it to the ``render_object`` tag and it will know how to
output it in your template.
This is generally useful when you need to render a list of objects of many
types, or when you need to display an object but don't know ahead of time what
type it is. For example, if your site search returns a list of objects from
various models, you can simply loop over them and use ``render_object``.
Usage::
{% render_object [object] for "[position]" as [varname] %}
The ``object`` argument should be a reference to the actual object to be
rendered. The remaining arguments (described below) are all optional.
By default, the tag will attempt to render the ``object`` by choosing the first
template from the following locations::
"render/[app_label]_[model_name].html"
"render/default.html"
If no template is found, the tag will output an empty string. When a template
is found, it will receive the same context as the original template, plus an
``object`` variable which holds the model object.
If you specify ``for "[position]"``, you can give a single model different
representations for different locations throughout your site. If you include a
``position`` argument, ``render_object`` will add a couple templates to the top
of the list, like so::
"render/[position]/[app_label]_[model_name].html"
"render/[position]/default.html"
"render/[app_label]_[model_name].html"
"render/default.html"
If you specify ``as [varname]``, the tag will place the rendered text into a
context variable instead of outputting it to the template.
"""
bits = token.split_contents()
varname = None
position = None
if bits[-2] == 'as':
# Get the varname, if specified
varname = bits[-1]
bits = bits[:-2]
if bits[-2] == 'for':
# Get the position, if specified
position = bits[-1]
bits = bits[:-2]
if len(bits) != 2:
raise template.TemplateSyntaxError("%r tag has two required arguments" % bits[0])
return RenderObjectNode(bits[1], position, varname)
register.tag('render_object', do_render_object)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 8 months ago
Comments
Please login first before commenting.