2

Let's say I have an object 'users' coming in as a context, which I know contains many user objects. Now, in my template, I want to access a specific user which I know has a specific property value (let's say id of 10), and then display another property associated with that user. I know that I can do:

{% for user in users %}
    {% if user.id == 10 %}
        {{ user.age }}
    {% endif %}
{% endfor %}

I know that I could extract that user in my view and pass just that one object (?) but in this case it makes sense to have all of them.

I feel that there ought to be an easier way to do this but I'm a Django/templating newbie. Tried searching but wasn't sure how to phrase it..

pete
  • 2,739
  • 4
  • 32
  • 46
  • How does it make sense to have all of them when you only care about one? – Ignacio Vazquez-Abrams Jan 17 '14 at 00:11
  • @Ignacio: Per my post, I need all of them for other display purposes. In my case, it's not really users (i used it as a simple example) -- I need to get pricing info for different subscription plans to display under their respective renew/upgrade buttons (which themselves are displayed based on other conditions).. – pete Jan 17 '14 at 00:14
  • 2
    I would personally handle this in the view, that way you can at least write unit tests for the logic. Putting loads of logic directly into the template can make it harder to reuse it and keep your code DRY: http://programmer.97things.oreilly.com/wiki/index.php/Don't_Repeat_Yourself – aychedee Jan 17 '14 at 00:37

2 Answers2

3

this is really a job for template tags

templatetags/my_tags.py

...
@register.filter
def where_id(users,user_id):
    return filter(lambda u:u.pk==user_id,users)
...

sometemplate.html

{%load my_tags %}
...
{% for user in users|where_id:10 %}
....
Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
  • Thanks, was just looking at tags & filter docs yesterday. Tried implementing per above but getting a syntax error. I don't know 'lambdas' yet -- anyone willing to translate into non-lambda code? :) – pete Jan 17 '14 at 00:46
  • @pete It's equivalent to `def foo(x): return x.pk==user_id`, where `user_id` is a global varibale – Steinar Lima Jan 17 '14 at 00:58
  • 2
    You have to use `from django.template import Library; register = Library()`. – Steinar Lima Jan 17 '14 at 01:01
  • Yes, I got that, thanks. I'm getting an "AttributeError at /account/ pk". In my case, the attribute I'm filtering by is a string. Would it break your solution? – pete Jan 17 '14 at 01:08
  • 2
    a) This is not my solution (mine is the one below) and b) you have to change `u.pk` to `u.` if you choose to go for this solution – Steinar Lima Jan 17 '14 at 01:11
0

If you are working with unique fields, it might be better to use get, rather than filter. Here's a generic way to do that, inspired by Joran's answer and this answer.

my_template.html:

{%load my_tags %}
...
This is the user with pk=1: {{ users|get:"pk, 1" }}
....

templatetags/my_tags.py:

from django.template import Library
from django.core.exceptions import ObjectDoesNotExist

register = Library()

@register.filter
def get(models, argstring):
    args = argstring.split(',')
    if len(args) != 2:
        raise ValueError("Exactly two arguments required, separated by comma")
    field, value = args
    try:
        return models.get(**{field: value})
    except ObjectDoesNotExist:
        return None
Community
  • 1
  • 1
Steinar Lima
  • 7,644
  • 2
  • 39
  • 40