- Author:
- waterson
- Posted:
- September 27, 2007
- Language:
- Python
- Version:
- .96
- Score:
- 4 (after 4 ratings)
I've been working on a project where I realized that I wanted to call methods on Python objects with arguments from within a Django template.
As a silly example, let's say your application maintains users and "permissions" that have been granted to them. Say that permissions are open-ended, and new ones are getting defined on a regular basis. Your User
class has a check_permission(p)
method that return True
if the user has been granted the permission p
.
You want to present all the users in a table, with one row per user. You want to each permission to be presented as a column in the table. A checkmark will appear in cells where a user has been granted a particular permission. Normally, in order to achieve this, you'd need to cons up some sort of list-of-dicts structure in Python and pass that as a context argument. Ugh!
Here's how you'd use the method
, with
, and call
filters to invoke the check_permission
method from within your template. (Assume that you've provided users
and permissions
as context variables, with a list of user and permission objects, respectively.)
<table>
<tr>
<th></th>
{% for p in permissions %}
<th>{{ p.name }}</th>
{% endfor %}
</tr>
{% for u in users %}
<tr>
<td>{{ u.name }}</td>
{% for p in permissions %}
<td>
{% if user|method:"check_permission"|with:p|call" %}X{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
The call_with
method is a shortcut for single-argument invocation; for example, we could have re-written the above as
{% if user|method:"check_permission"|call_with:p %}...{% endif %}
Anyway, this has been useful for me. Hope it's helpful for others!
--chris
P.S., tip o' the cap to Terry Weissman for helping me polish the rough edges!
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 | from django.template import Library
from functools import partial
register = Library()
@register.filter
def method(value, arg):
"""
Prepare the specified object for invoking a method.
This is used in conjunction with the "with" and "call" tags. For
example, with
class Foo:
def bar(self, a, b, c):
return "a is %s, b is %b, c is %c" % (a, b, c)
def bop(self, a):
return "a is %s" % a
and { "foo": Foo() } passed to the template, then:
foo|method:"bar"|with:"one"|with:"two"|with:"three"|call
will invoke foo("one", "two", "three"), and emit:
a is one, b is two, c is three.
Alternatively,
foo|method:"bop"|call_with:"baz"
is a bit of a short cut.
"""
if hasattr(value, str(arg)):
return getattr(value, str(arg))
return "[%s has no method %s]" % (value, arg)
@register.filter
def call_with(value, arg):
"""
Call a function with the specified argument.
Meant to be used with the "method" tag.
"""
if not callable(value):
return "[%s is not callable]" % value
return value(arg)
@register.filter
def call(value):
"""
Call a function with no arguments.
Meant to be used with the "method" tag.
"""
if not callable(value):
return "[%s is not callable]" % value
return value()
@register.filter(name="with")
def with_(value, arg):
"""
Accumulate the specified positional argument.
Meant to be used with the "method" tag.
"""
if callable(value):
return partial(value, arg)
return "[%s is not callable]" % value
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 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.