5 ms·
The included simple_tag and filter decorators should be used for simple tags and filters. More sophisticated tags can specify a separate renderer class, which m
by erlanger 16y ago
The included simple_tag and filter decorators should be used for simple tags and filters. More sophisticated tags can specify a separate renderer class, which must be what you mean by "boilerplate."
from django.core.urlresolvers import reverse
from django.template import Library
register = Library()
@register.simple_tag
def menu_item(req, viewname, label):
url = reverse(viewname)
cls = ''
if url == req.path:
cls += 'active'
return '<li class="%s"><a href="%s">%s</a></li>' % (cls, url, label)
Using the tag:
{% menu_item request 'accounts.views.profile' 'Your Account' %}
The only part of that I don't like is passing the request, but I'm willing to bet there's a simpler way to access the request object from the function.
A simple filter:
@register.filter
def subtract(x, y):
"""Subtracts the arg from the value"""
return int(x) - int(y)
And maybe in a for loop for overlapping elements:
<li style="z-index: {{ 100|subtract:forloop.counter }}">
Yes, I use two spaces in my Python code too.
- stevenwei 16y agoI'm not really a big fan of how writing custom template tags throws you back into the land of string substitution: the entire problem that templating languages were meant to solve in the first place! Jinja2's macros are a much more elegant solution, IMO.
- zeemonkee 16y agoThe above solution is just plain ugly, HTML in Python. Another PITA, where Django templates just fall down, is forms. Suppose you have a form: class MyForm(forms.Form): name = forms.CharField() You then add that in the template: {{ form.name }} All well and good; but what if you want to change the size, maxlength, or add a class ? These things clearly belong in the template, but no, you have to either add them in the form declaration: name = forms.CharField(widget=forms.TextInput(attrs={'class' : 'foo'})) or in the view: form.fields['name'].widget.attrs = {'class' : 'foo'} Both of which clearly break the separation of concerns. yes, you could write a template tag to get around this; but it's not in standard Django. Contrast the following in Jinja2 (using WTForms, but you get the idea): {{ form.name(class_="foo") }}
- simonw 16y agoI agree that this is pretty frustrating - it's one of the things my django-html package addresses: http://github.com/simonw/django-html http://github.com/simonw/django-html {% field form.name class="myclass" %}
- zeemonkee 16y agoI had a similar workaround in a project, it did something like this: {% form.name|attrs:"class='foo', maxlength=20" %} If Django templates allowed function calls however (as Jinja2 does) that would eliminate the need for a lot of these tags.
- metamemetics 16y ago>All well and good; but what if you want to change the size, maxlength, or add a class ? Adding a class: Django gives every element of the form id values for easy styling in CSS. Just do {{form.as_p}} and see what it outputs. size and max length: I'm fine with these in python as they correspond to the max-length that would be validated into a data member. If you mean pixel size on screen, this belongs neither in HTML or your template but in CSS, since browsers render forms completely differently regardless of their HTML attributes, you have to style their width\height in CSS to get anything consistent.
- erlanger 16y agoUnfortunately, the defaults stink. 1.2 remedies this for error messages at least. as_p and co. should include some class describing the field type in the outer <p> tag so that a developer can style the label and error messages in a way specific to the field type.