If you've ever wanted to dynamically lookup values in the template layer (e.g. `dictionary[bar]`), then you've probably realized/been told to do this in the python layer. The problem is then you often to build a huge 2-D list to hold all of that data.
These are two solutions to this problem: by using generators we can be lazy while still making it easy in the python layer. I'm going to write more documentation later, but here's a quick example:
from lazy_lookup import lazy_lookup_dict
def some_view(request):
users = User.objects.values('id', 'username')
articles = Article.objects.values('user', 'title', 'body')
articles = dict([(x['user'], x) for x in articles])
return render_to_response('some_template.html',
{'data': lazy_lookup_dict(users, key=lambda x: x['id'],
article=articles,
item_name='user')})
Then in the template layer you'd write something like:
{% for user_data in data %}
{{ user_data.user.username }}, {{ user_data.article.title }}
{% endfor %}
- template
- dynamic
- lookup
- lazy
- dynamic-lookup
Based on jspacker by Dean Edwards,
Python port by Florian Schulze: http://www.crowproductions.de/repos/main/public/packer/jspacker.py
Packs javascript
Example usage::
{% packjs %}
var a = 1;
var b = 2;
var c = 3;
alert(a+b);
{% endpackjs %}
This example would return this script::
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[c]=k[c]||c;k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp("\\b"+e(c)+"\\b","g"),k[c]);return p}('0 5 = 1;\n 0 4 = 2;\n 0 7 = 3;\n 6(5+4);\n',8,8,'var||||b|a|alert|c'.split('|'),0,{}))
- templatetag
- javascript
- pack
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!
- filter
- filters
- function
- object
- method