Login

Functional Filters

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

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 1 week ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 9 months, 4 weeks ago
  5. Help text hyperlinks by sa2812 10 months, 3 weeks ago

Comments

Please login first before commenting.