I have the following code in my Django template:
{% for matrix_row in request.session.matrix_rows %}
{% for radio in form.matrix_row_one_column_value %}
<li>{{ radio }}</li>
{% endfor %}
{% endfor %}
How can I change the list for the inner for loop as the outer for loop is iterated over? For example, the lists for successive passes of the outer for loop should be as follows:
form.matrix_row_one_column_value
form.matrix_row_two_column_value
form.matrix_row_three_column_value
form.matrix_row_four_column_value
form.matrix_row_five_column_value
form.matrix_row_six_column_value
Any help would be appreciated. Thanks.
Why don't you do the work in the view instead of trying to come up with something complicated in the template?
For example, in your Python:
names = ['apple', 'orange', 'carrot']
colors = [ ['red', 'green'], ['orange', 'red'], ['orange', 'yellow'] ]
fruits = zip(names, colors)
And then in your template:
{% for name, colors in fruits %}
<div>
{{ name }} -
{% for color in colors %}
{{ color }}
{% endfor %}
</div>
{% endfor %}
If I understand you correctly, what you want to do is something like form[matrix_row]
{% for matrix_row in request.session.matrix_rows %}
{% for radio in form[matrix_row] %}
<li>{{ radio }}</li>
...
That isn't possible in Django templates, so you would need to add your own simple templatetag for that. Something like this
#register.filter
def keyvalue(dic, key):
"""Use a variable as a dictionary key"""
return dic[key]
And now you can do
{% for matrix_row in request.session.matrix_rows %}
{% for radio in form|keyvalue:matrix_row %}
<li>{{ radio }}</li>
...
Related
I try to rebuild this example:
https://blog.roseman.org.uk/2010/01/11/django-patterns-part-2-efficient-reverse-lookups/
I have a model "Product" and a model "Order". Order has a foreignkey to "product". So for 1 Product I have N Orders
In my template I have to display a lot of information so I would like to avoid to do "for order in Product.order_set.all()" in my template
In my template, if I write :
{{ object_list.1.related_items }}
everything is fine and I get what I want
but if I write:
{% for i in object_list %}
{{ object_list.i.related_items }}
{% endfor %}
I don't get a result.
Can somebody tell me how I solve this problem?
My object_list is nearly the same as in the above example:
products = Product.objects.all()
i = 0
qs = Product.objects.all()
obj_dict = dict([(obj.id, obj) for obj in qs])
objects = Order.objects.filter(producttyp__in=qs)
relation_dict = {}
for obj in objects:
relation_dict.setdefault(obj.producttyp_id, []).append(obj)
for id, related_items in relation_dict.items():
obj_dict[id].related_items = related_items
def get(self,request,*args,**kwargs):
context = {'object_list':self.obj_dict}
return render(request,self.template_name,context)
the only change i did is from
obj_dict[id]._related_items to obj_dict[id].related_items because of the not allowed underscore?!
How do I print the list in my template like:
- Product A
- Order 1
- Order 2
- Order 5
- Product B
- Order 3
- Order 6
best regards
That is logical, since here Django interprets i not as the variable, but as the an identifier, so it aims to access object_list.i, or object_list['i'], not object_list.1 for example.
You however do not need i here, you can just access the related_items of the object, like:
{% for object in object_list %}
{{ object.related_items }}
{% endfor %}
If related_items is, as the name suggests, a collection as well, we can iterate over these items as well:
{% for object in object_list %}
{% for subitem in object.related_items %}
{{ subitem }}
{% endfor %}
{% endfor %}
for a dictionary, we can access the .values, like:
{% for object in object_dict.values %}
{{ object.related_items }}
{% endfor %}
EDIT: as for the specific case of the listview. You can use .prefetch_related to fetch all the relations with one extra query:
class MyListView(ListView):
queryset = Product.objects.prefetch_related('order_set')
template = 'my_template.html'
In the template you can then render this like:
<ul>
{% for product in object_list %}
<li>{{ product }}</li>
<ul>
{% for order in product.order_set %}
<li>{{ order }}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
I have a list that looks like this:
[(u'Element1', u'Description1', u'Status1), (u'newElement2', u'newDescription2', u'newStatus2), (u'nextElement3', u'nextDescription3', u'nextStatus3), (u'anotherElement4', u'anotherDescription4', u'anotherStatus4)]
I have an ansible playbook that uses a jinja2 template to render the list to a text file. The template file looks like this:
{% for item in description | batch(3, ' ') %}
{% for el in item %}
{{ el }}
{% endfor %}
{% endfor %}
But this returns the text file to look like this:
[u'Element1', u'Description1', u'Status1]
[u'newElement2', u'newDescription2', u'newStatus2]
[u'nextElement3', u'nextDescription3', u'nextStatus3]
[u'anotherElement4', u'anotherDescription4', u'anotherStatus4]
What I want the report to look like is this:
Element1 Description1 Status1
newElement2 nextDescription2 newStatus2
nextElement3 nextDescription3 nextStatus3
anotherElement4 anotherDescription4 anotherDescription4
Is there a way to remove the unicode characters and render the lists this way?
For example:
{% for row in description %}
{% for cell in row %}
{{ "%-22s"|format(cell) }}
{%- endfor %}
{% endfor %}
Yields:
Element1 Description1 Status1
newElement2 newDescription2 newStatus2
nextElement3 nextDescription3 nextStatus3
anotherElement4 anotherDescription4 anotherStatus4
But to get a dynamic padding - depending on a max length of an element in a column - looks like a much more complex task: {{ "%-22s"|format(cell) }} can be replaced with {{ "{0}".format(cell).ljust(width) }} where width can be a variable, but likely it would require another loop first to collect the lengths.
You could try
{% for el in item %}
{% for e in el %}
{{ e }}
{% endfor %}
{% endfor %}
Or use html tables if you want to be able to change formatting
I've got a Django template I'd sometimes like to pass a list and sometimes like to pass a single value. How can the template tell which it was given?
I'm thinking the value would be set like one of these:
context = {
'foo' : 'bar
}
or:
context = {
'foo' : ['bar', 'bat', 'baz']
}
Then, the template would have code that looks something like this:
{% if foo isa list %}
{% for item in foo %}
{{ item }}<br>
{% endfor %}
{% else %}
{{ item}}<br>
{% endif %}
I can set it up to have foo or foolist, for example, and check for one or the other. However, it'd be a bit nicer (imo) to just have foo that was either a list or not.
If you intend to do it this way then just add a check that it doesn't have format(in case of string) method and has 0 index, if so then its a list else considered single value
{% if foo.0 and not foo.format %}
{% for item in foo %}
{{ item }}<br>
{% endfor %}
{% else %}
{{ item}}<br>
{% endif %}
I think your approach is needlessly complicated.
I would just go with a list:
views.py
foo_list = ['bar']
context = {
'foo': foo_list,
'foo_len': len(foo_list),
}
template
{% if foo_len == 1 %}
{{ foo.0 }}
{% else %}
{% for item in foo %}
{{ item }}
{% endfor %}
{% endif %}
My dictionary looks like this(Dictionary within a dictionary):
{'0': {
'chosen_unit': <Unit: Kg>,
'cost': Decimal('10.0000'),
'unit__name_abbrev': u'G',
'supplier__supplier': u"Steve's Meat Locker",
'price': Decimal('5.00'),
'supplier__address': u'No\r\naddress here',
'chosen_unit_amount': u'2',
'city__name': u'Joburg, Central',
'supplier__phone_number': u'02299944444',
'supplier__website': None,
'supplier__price_list': u'',
'supplier__email': u'ss.sss#ssssss.com',
'unit__name': u'Gram',
'name': u'Rump Bone',
}}
Now I'm just trying to display the information on my template but I'm struggling. My code for the template looks like:
{% if landing_dict.ingredients %}
<hr>
{% for ingredient in landing_dict.ingredients %}
{{ ingredient }}
{% endfor %}
Print {{ landing_dict.recipe_name }}
{% else %}
Please search for an ingredient below
{% endif %}
It just shows me '0' on my template?
I also tried:
{% for ingredient in landing_dict.ingredients %}
{{ ingredient.cost }}
{% endfor %}
This doesn't even display a result.
I thought perhaps I need to iterate one level deeper so tried this:
{% if landing_dict.ingredients %}
<hr>
{% for ingredient in landing_dict.ingredients %}
{% for field in ingredient %}
{{ field }}
{% endfor %}
{% endfor %}
Print {{ landing_dict.recipe_name }}
{% else %}
Please search for an ingredient below
{% endif %}
But this doesn't display anything.
What am I doing wrong?
Lets say your data is -
data = {'a': [ [1, 2] ], 'b': [ [3, 4] ],'c':[ [5,6]] }
You can use the data.items() method to get the dictionary elements. Note, in django templates we do NOT put (). Also some users mentioned values[0] does not work, if that is the case then try values.items.
<table>
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
{% for key, values in data.items %}
<tr>
<td>{{key}}</td>
{% for v in values[0] %}
<td>{{v}}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
Am pretty sure you can extend this logic to your specific dict.
To iterate over dict keys in a sorted order - First we sort in python then iterate & render in django template.
return render_to_response('some_page.html', {'data': sorted(data.items())})
In template file:
{% for key, value in data %}
<tr>
<td> Key: {{ key }} </td>
<td> Value: {{ value }} </td>
</tr>
{% endfor %}
This answer didn't work for me, but I found the answer myself. No one, however, has posted my question. I'm too lazy to
ask it and then answer it, so will just put it here.
This is for the following query:
data = Leaderboard.objects.filter(id=custom_user.id).values(
'value1',
'value2',
'value3')
In template:
{% for dictionary in data %}
{% for key, value in dictionary.items %}
<p>{{ key }} : {{ value }}</p>
{% endfor %}
{% endfor %}
If you pass a variable data (dictionary type) as context to a template, then you code should be:
{% for key, value in data.items %}
<p>{{ key }} : {{ value }}</p>
{% endfor %}
I am thankful for the above answers pointing me in the right direction. From them I made an example for myself to understand it better. I am hoping this example will help you see the double dictionary action more easily and also help when you have more complex data structures.
In the views.py:
bigd = {}
bigd['home'] = {'a': [1, 2] , 'b': [3, 4] ,'c': [5,6] }
bigd['work'] = {'e': [1, 2] , 'd': [3, 4] ,'f': [5,6] }
context['bigd'] = bigd
In the template.html:
{% for bigkey, bigvalue in bigd.items %}
<b>{{ bigkey }}</b> <br>
{% for key, value in bigvalue.items %}
key:{{ key }} <br>
----values: {{ value.0}}, {{value.1 }}<br>
{% endfor %}
<br>
{% endfor %}
Notice the list in the second dictionary is accessed by the index in the list.
Result in browser is something like:
In my views.py, I'm building a list of two-tuples, where the second item in the tuple is another list, like this:
[ Product_Type_1, [ product_1, product_2 ],
Product_Type_2, [ product_3, product_4 ]]
In plain old Python, I could iteration the list like this:
for product_type, products in list:
print product_type
for product in products:
print product
I can't seem to do the same thing in my Django template:
{% for product_type, products in product_list %}
print product_type
{% for product in products %}
print product
{% endfor %}
{% endfor %}
I get this error from Django:
Caught an exception while rendering: zip argument #2 must support iteration
Of course, there is some HTML markup in the template, not print statements. Is tuple unpacking not supported in the Django template language? Or am I going about this the wrong way? All I am trying to do is display a simple hierarchy of objects - there are several product types, each with several products (in models.py, Product has a foreign key to Product_type, a simple one-to-many relationship).
Obviously, I am quite new to Django, so any input would be appreciated.
Another way is as follows.
If one has a list of tuples say:
mylst = [(a, b, c), (x, y, z), (l, m, n)]
then one can unpack this list in the template file in the following manner.
In my case I had a list of tuples which contained the URL, title, and summary of a document.
{% for item in mylst %}
{{ item.0 }} {{ item.1}} {{ item.2 }}
{% endfor %}
it would be best if you construct your data like {note the '(' and ')' can be exchanged for '[' and ']' repectively, one being for tuples, one for lists}
[ (Product_Type_1, ( product_1, product_2 )),
(Product_Type_2, ( product_3, product_4 )) ]
and have the template do this:
{% for product_type, products in product_type_list %}
{{ product_type }}
{% for product in products %}
{{ product }}
{% endfor %}
{% endfor %}
the way tuples/lists are unpacked in for loops is based on the item returned by the list iterator.
each iteration only one item was returned. the first time around the loop, Product_Type_1, the second your list of products...
You must used this way:
{% for product_type, products in product_list.items %}
{{ product_type }}
{% for product in products %}
{{ product }}
{% endfor %}
{% endfor %}
Don't forget the variable items in the dictionary data
If you have a fixed number in your tuples, you could just use indexing. I needed to mix a dictionary and the values were tuples, so I did this:
In the view:
my_dict = {'parrot': ('dead', 'stone'), 'lumberjack': ('sleep_all_night', 'work_all_day')}
In the template:
<select>
{% for key, tuple in my_dict.items %}
<option value="{{ key }}" important-attr="{{ tuple.0 }}">{{ tuple.1 }}</option>
{% endfor %}
</select>
Just send the template a list of product types and do something like:
{% for product_type in product_type_list %}
{{ product_type }}
{% for product in product_type.products.all %}
{{ product }}
{% endfor %}
{% endfor %}
It's been a little while so I can't remember exactly what the syntax is, let me know if that works. Check the documentation.