I am trying to access values in my Django template (using Jinja2) from an API and am struggling quite a bit. I'm new to Python/Django/programming and am having a hard time navigating through this complex nested structure of lists/dicts.
Here is a snippet of the API response for a single flight (the response contains a total of 250 flights):
{
"meta": {
"count": 2
},
"data": [
{
"type": "flight-offer",
"id": "1",
"source": "GDS",
"instantTicketingRequired": false,
"nonHomogeneous": false,
"oneWay": false,
"lastTicketingDate": "2020-11-20",
"numberOfBookableSeats": 2,
"itineraries": [
{
"duration": "PT22H40M",
"segments": [
{
"departure": {
"iataCode": "GIG",
"terminal": "2",
"at": "2020-12-01T16:30:00"
},
"arrival": {
"iataCode": "CDG",
"terminal": "2E",
"at": "2020-12-02T07:45:00"
},
"carrierCode": "AF",
"number": "443",
"aircraft": {
"code": "77W"
},
"operating": {
"carrierCode": "AF"
},
"duration": "PT11H15M",
"id": "3",
"numberOfStops": 0,
"blacklistedInEU": false
},
{
"departure": {...
For each flight I would like to extract the following key/values:
id
duration
iataCode
Below is what I have tried so far...
id (successful)
{% for flight in data %}
{{ flight.id }}
{% endfor %}
iataCode (unsuccessful)
{% for flight in data %}
{% for itinerary in itineraries %}
{% for segment in segments %}
{{ departure.iataCode }}
{% endfor %}
{% endfor %}
{% endfor %}
iataCode (unsuccessful)
{% for itineraries, itinerary in data %}
{% for segments, segment in itineraries %}
{{ departure.iataCode }}
{% endfor %}
{% endfor %}
{% endblock %}
Would be very appreciative of any advice here.
Thank you!
You have to "follow" the loop variable.
{% for flight in data %}
{% for itinerary in flight.itineraries %}
{% for segment in itinerary.segments %}
{{ segment.departure.iataCode }}
{% endfor %}
{% endfor %}
{% endfor %}
Related
Is there a way to specify different labels for the inner and outer ring in a nested pie/doughnut chart?
Example of nested pie chart with inner and outer pie/doughnut
In my specific example I am using the outer ring as a "detail view" (with many individual names) but I am using the inner ring to group together a number of the items - specifically, the "red" items in the outer ring are then grouped together for the inner ring. To this end I am looking to have the inner ring's red item named something like "group", but at present, since there are two items in the inner ring, the first two labels are being used.
Let me know if that makes sense or if more explanation is required!
For your reference here is the code used to generate the chart - the data itself is coming from a Flask app using the Jinja2 templating language, hence the {% for %} loops.
(I'm also VERY new to using ChartJS with Flask in this way so if there are best practices that I am ignoring/not aware of then please let me know!)
// Pie chart
const pieData = {
labels: ["99% of composers",
{% for c in one_percent_of_composers_list %}
{% for k,v in c.items() %}
'{{k}}',
{% endfor %}
{% endfor %}
],
datasets: [
{
// OUTER PIE
label: 'Performance Numbers',
data: [
{{everyone_else_performance_time}},
{% for c in one_percent_of_composers_list %}
{% for k,v in c.items() %}
{{v|round|int}},
{% endfor %}
{% endfor %},
],
backgroundColor: [
'rgb(54, 162, 235)',
{% for c in one_percent_of_composers_list %}
{% for k,v in c.items() %}
'rgb(193, 16, 36)',
{% endfor %}
{% endfor %}
],
hoverOffset: 4
},
{
// INNER PIE
label: 'Composer Numbers',
data: [
{{everyone_else_list|length}},
{{one_percent_of_composers_list|length}},
],
backgroundColor: [
'rgb(54, 162, 235)',
{% for c in one_percent_of_composers_list %}
{% for k,v in c.items() %}
'rgb(193, 16, 36)',
{% endfor %}
{% endfor %}
]
}
]
};
const pieConfig = {
type: 'doughnut',
data: pieData,
options:{
plugins:{
legend:{
position:'bottom'
}
}
},
plugins: [counter]
};
TIA!
Rich
So I have this JSON response:
{
"orders": [
{
"orderId": "4123456789",
"dateTimeOrderPlaced": "2017-02-09T12:39:48+01:00",
"orderItems": [
{
"orderItemId": "2012345678",
"ean": "0000007740404",
"cancelRequest": false,
"quantity": 10
}
]
}
]
}
I passed it in my view with the .json() method. I use this in my template:
{% for key, value in orders.items %}
{{ key }}: {{ value }}
{% endfor %}
I get this in my HTML:
orders: [{'orderId': '2529081520', 'dateTimeOrderPlaced': '2019-09-07T00:12:16+02:00', 'orderItems': [{'orderItemId': '2298728074', 'ean': '8945005881389', 'cancelRequest': False, 'quantity': 1}]}]
But how to dissect it further? For example to get the OrderId or the ean?
You can access dictionary items with the template variable dot-notation, like this
{% for order in orders.orders %}
{{ order.orderId }}
{% for item in order.orderItems %}
{{ item.ean }}
{% endfor %}
{% endfor %}
Assuming the context variable orders contains your parsed JSON, this template would be rendered like this:
OrderId: 4123456789
EAN: 0000007740404
How do I traverse and display the dict "index name" or "key name" in Django Template? Below is the dict from the context.
Basically this is the structure of my dict all_options[category][sub_category][name]. "Category, sub_Category and name" are dynamic. I wanted to display "Category" first then drill down to "Sub Category" then drill further down.
Templates doesn't allow using square braces to access the dict attribute.
Thanks in advance!
Context
'Condenser (WC)': {
'Water Box': {
'2MPA Condenser Water Box': {
'option': '2MPA Condenser Water Box',
'chillers': [{
'chiller': 'xxxxxxxxxxx',
'factory': '2' ,
'option': 'WB240.2U.F2HVKA>
}, {
'chiller': 'xxxxxxxxxxx',
'factory': '1' ,
'option': 'WB088.2H.F2AYFA>
}]
},
},
'Anodes': {
'Magnesium Anodes': {
'option': 'Magnesium Anodes',
'chillers': [{
'chiller': 'xxxxxxxxxxx',
'factory': '2' ,
'option': 'WB240.2U.F2HVKA>
}, {
'chiller': 'xxxxxxxxxxx',
'factory': '2' ,
'option': 'WB240.2U.F2HVKA>
}]
}
},
'Stainless Steel Tube Sheet': {
'304 SS Condenser Tube Sheets': {
'option': '304 SS Condenser Tube Sheets',
'chillers': [{
'chiller': 'xxxxxxxxxxx',
'factory': '2' ,
'option': 'WB240.2U.F2HVKA>
}]
},
}
},
Template
In the template, I added a comment and it's the string that needs to be printed.
{% for category_name in all_options %}
{{ category_name }} #Condenser (WC)
{% for subcat in category_name %}
{{ subcat }} #Water Box
{% for item in subcat %}
{{ item }} #2MPA Condenser Marine Water Box
{% for chiller in item.chillers %}
{{ chiller.option }} #WB200.3K.F2HVKA
{% endfor%}
{% endfor%}
{% endfor%}
{% endfor %}
In Python you can iterate over a iterable if 2-tuples, by calling the .items() function on the dictionary. In Django templates, we can do this as well:
{% for category_name, category in all_options.items %}
{{ category_name }} #Condenser (WC)
{% for subcat_name, subcat in category.items %}
{{ subcat_name }} #Water Box
{% for item_name, item in subcat.items %}
{{ item_name }} #2MPA Condenser Marine Water Box
{% for chiller in item.chillers %}
{{ chiller.option }} #WB200.3K.F2HVKA
{% endfor%}
{% endfor%}
{% endfor%}
{% endfor %}
(or something similar to this)
So here category_name is the key associated with the the dictionary item, and category is the value (so in this case a dictionary as well*). You can then for example enumerate again over that dictionary, and so on.
Note that in Python dictionaries are unordered: so that means that iteration can happen in any order possible. In case you want a fixed order, I advice you to use a list of 2-tuples, in which case you do not have to call .items of course. Furthermore a dictionary can contain only hashable keys, and every key can occur at most once. This is not because of Django, it is simply how dictionaries are designed in Python.
As said before, in case you want an ordered collection of elements such that the "key" does not has to be hashable and/or occur multiple times, I would advice you to use a list of 2-tuples (something like [(k1, v1), (k2, v2)] with ki the key, and vi the corresponding value).
In case you are only interested in the values, you can use .values, which will produce an iterable over the values of the dictionary.
I've read this, and I have an array like that:
context[u'erreurs'] = {
'aa': {'titres': [], 'liste': [], 'urls': []},
'bb': {'titres': [], 'liste': [], 'urls': []},
'...': {'titres': [], 'liste': [], 'urls': []}
}
If there's an error, 'titres', 'liste' and 'urls' become array of strings, filled with adequates values.
In my template, if erreur is set I do this:
{% for idx, tab in erreurs.items %}
<ul>
{% for e in tab.liste %}
{% if user.is_authenticated %}
<li>{{ e }}</li>
{% else %}
<li>{{ e }}</li>
{% endif %}
{% endfor %}
</ul>
{% endfor %}
I would like to use the current index to use the value that is in another array, here: tab.urls. It doesn't work and gives me the error:
Could not parse the remainder: '[forloop.counter0]' from 'tab.urls[forloop.counter0]'
How to solve this?
Unfortunately, Django's templates don't support such syntax. You should put together a custom template filter:
# yourapp/templatetags/yourapp_tags.py:
from django import template
register = template.Library()
#register.filter
def at_index(array, index):
return array[index]
and use it like:
{% load yourapp_tags %}
{{ tab.urls|at_index:forloop.counter0 }}
You need to make an actual model that represents the data then the task becomes trivial
class YourModel(object):
titre = ''
liste = ''
url = ''
context[u'erreurs'] = {
'aa': [], # List of model
}
{% for idx, tab in erreurs.items %}
<ul>
{% for model in tab %}
{{ model.titre }}
{{ model.liste }}
{{ model.url }}
{% endfor %}
</ul>
{% endfor %}
Can something like this be done in django?
{% for item in lst %}
{{ something_{{ item }} }}
{% endfor %}
Args passed to render would be for example:
{"lst": range(3), "something_0": "aaa", "something_1": "aaa", "something_2": "aaa"}
No. Structure your data as a list of dicts.
[
{'something': 'aaa', 'something_else': 'bbb', ...},
{'something': 'ccc', 'something_else': 'ddd', ...},
...
]
and now:
{% for item in lst %}
{{ item.something }}
{{ item.something_else }}
{% endfor %}