Jayd
Jayd

Reputation: 930

Use for loop variable as dictionary key in Django template

I am trying to get the following working.

The count loop needs to loop through for all values, and there may not be a user associated with each count, but the count value i needs to be used in each loop to pass to the JavaScript.

python part:

users = {}
users[1]={}
users[1][id]=...
users[1][email]=...

...

count=[1,2,3,4,5,6,7,8,9,10]

Django template part:

{% for i in count %}
do some stuff with the value i using {{i}} which always returns the value, i.e. 1

email:{% if users.i.email %}'{{users.i.email}}'{% else %}null{% endif%}
{% endfor %}

This returns nothing for email. When I substitute the number 1 for i in {% if user.i.email %} email returns the users email address. I'm using the data in JavaScript, so it needs to be implicitly null if it doesn't exist. I can't seem to get Django to recognize the i variable as a variable instead of the value i.

using [] doesn't work, as it throws an invalid syntax error

email:{% if users.[i].email %}'{{users.[i].email}}'{% else %}null{% endif%}

I have tried using "with" statement

{% for i in count %}{% with current_user=users.i %}...

and then using current_user.email, but returned nothing

Have also tried

{% for i in count %}{% with j=i.value %}...

just in case it would work, and then trying to use j, but same result.

I have thought about creating an inner for loop that loops over the user object and check if i is equal to the key/value, but that seems expensive and not very scalable.

Any ideas how I can force Django to view i as a variable and use it's value as an index, or any other way get around this?

Thanks

Jayd

*Edit:

I tried the extra for loop, as suggested by Abhi, below.

{% for i in count %}
  {% for key, current_user in users.items %}
      do some stuff with the value i using {{i}} which always returns the value, i.e. 1
      email:{% if i == key and current_user.email %}'{{current_user.email}}'{% else %}null{% endif%}
  {% endfor %}
{% endfor %}

This sort of works, but now it will repeat do some stuff with the value i for every value of users. and if I put in an if:

{% for i in count %}
  {% for key, current_user in users.items %}
    {% if i == key %}
      do some stuff with the value i using {{i}} which always returns the value, i.e. 1
      email:{% if i == key and current_user.email %}'{{current_user.email}}'{% else %}null{% endif%}
    {% endif%}
  {% endfor %}
{% endfor %}

That ignores the loops when a count doesn't have a particular user.

The only way I can see around this is the have the user loop at each place that I want to use current_user.

{% for i in count %}
      do some stuff with the value i using {{i}} which always returns the value, i.e. 1
      email:{% for key, current_user in users.items %}{% if i == key and current_user.email %}'{{current_user.email}}'{% else %}null{% endif%}{% endfor %}
{% endfor %}

And this seems very expensive to do. Any ideas?

I was thinking of maybe writing a filter that returns the values for users using i as the key:

{% with current_user=users|getuser:i %}

But I don't know if this will work or I will get the same error, where i is being passed as the value 'i' instead of a variable name.

I will give it a try so long.

*Edit

This didn't work. The filter worked using {{}} returning the object, but it didn't work inside the {% %} .

Thanks for the input

Upvotes: 6

Views: 7565

Answers (4)

Ibrahim
Ibrahim

Reputation: 69

to make Jayd Code usable with either list or dict, try this

@register.filter(name='dict_value_or_null')
def dict_value_or_null(dict, key):
    try:
        return dict[key]
    except:
        return 'null'

Upvotes: 1

Jayd
Jayd

Reputation: 930

I have come up with the following as a work around:

This is the filter code:

@register.filter(name='dict_value_or_null')
def dict_value_or_null(dict, key):
    if key in dict:
        return dict[key]
    else:
        return 'null'

Here is the template code

{% for i in count %}
      do some stuff with the value i using {{i}} which always returns the value, i.e. 1
      email:'{{users|dict_value_or_null:i|dict_value_or_null:'email'}}'
{% endfor %}

This works well, so I suppose that have my solution. But I still think this all could have been much easier if there was a way in the template system to force values inside {% %} to be treated as variables, instead of literals.

Is there a way to do this?

Thanks for the input

Upvotes: 1

Daniel Roseman
Daniel Roseman

Reputation: 599470

As Joe says in his comment, a dictionary is clearly the wrong data structure for the outer container. You should be using a list.

users = []
user = {'id':..., 'email': ...}
users.append(user)

...

{% for user in users %}
    {{ user.email }}
{% endfor %}

If you need the number of each user within the loop, you can use {{ forloop.counter }}.

Upvotes: 9

Abhi
Abhi

Reputation: 61

Try this:

{% for key,val in user.items %}
ID is {{ val.id }} and Email is {{ val.email }}
{% endfor %}

Upvotes: 1

Related Questions