Accessing a specific dictionary inside a dictionary - Django Templates - python

I have the following "example" dictionary
myDict = {obj1:{key_a1:value_a1, key_a2:value_a2, key_a3:value_a3} ,
obj2:{key_b1:value_b1, key_b2:value_b2, key_b3:value_b3} ,
obj3:{key_c1:value_c1, key_c2:value_c2, key_c3:value_c3} }
Where obj are some class objects.
What if I just want to iterate over the values belonging to key obj2 only, how would I do that inside a template?
I've tried
{% for node,manyResults in myDict[obj2].items %}
//Error: Could not parse the remainder: '[obj2].items' from 'dict[obj2].items'
and
{% for node,manyResults in myDict[obj2] %}
//Error: Could not parse the remainder: '[obj2]' from 'dict[obj2]'
and
{% for node,manyResults in myDict.obj2.items %}
//OR
{% for node,manyResults in myDict.obj2 %}
//Both no error, but the values don't appear
Is there any way to do this?

I don't think there is a way of doing this with Django templates, and that you should do as I said in my comments, which I'll rewrite here -- with some edits -- to summarize the hole thing up.
--
Maybe you are just complicating things. If those 3 dicts are all you'll need, I would add them separetelly to my context dict and use'em independently in the template.
You can also iterate over them as I said:
{% for key, item in myDict.items %}
{% for innerkey, inneritem in item.items %}
...
Also, your last example would work if 'objX' were strings, because django templates can map that. Otherwise, it would simply not find the identifier in its namespace (as you have realized).
Hope it helps.

Related

How to access a list's length in a template's code block for Django?

In a template, I have a variable of type list called "participants". I want to check if the length of the list is equal to 2, for example. I tried the following:
{{ participants | json_script:"participants"}}
{% if participants|length==2 %}
.....
{% endif %}
However, this does not work. The error I get is:
TemplateSyntaxError at /chat/lobby/
Could not parse the remainder: '==2' from 'participants.count==2'
Can someone point out a way to access a list's length in a template's code block? thank you for your time and consideration!
The problem is the (lack of) spacing around the == part. If you rewrite this to
{% if participants|length == 2 %}
…
{% endif %}
the template parser will no longer error.
That being said, a template is used for rendering logic, and while it is hard to tell, it looks that this is more business logic, which, as #MeL says belongs in the views.

can we pass array/list to template content blocks in django? python

I know we can pass variables to content blocks but are we able to pass list?
I know we can pass variables in this way
{% include "partials/pickUp-Order-Form.html" with form="form" %}
I tried passing list like this
{% include "partials/pickUp-Order-Form.html" with form=["list", "test"] %}
this wouldn't work though. I searched up and there doesn't seem to have such thing in documentations.
You need to pass a list in a variable or object, you can do it like this:
{% include "partials/pickUp-Order-Form.html" with form="list test".split %}
or you can create the variable first and then pass it to the include tag:
{% with "list test" as list %}
{% include "partials/pickUp-Order-Form.html" with form=list.split %}
{% endwith %}
The include django template tag can be used for loading and rendering HTML templates where the context/data that was passed to the original template gets passed.
You can find documentation about this functionality in the built-ins section.
So if you would like to include a template, of which original view that renders the template has the following context dict: {'word': 'Bird', 'power_level': 9001} you can render it inside another template with: {% include "word_template.html" with word="Not a Bird" power_level="470" %}, which will in turn change the values to the desired ones.
To answer the question:
It should work
Taking into consideration you include a template which will not use the list type as something else.

List comprehensions in Jinja

I have two lists:
strainInfo, which contains a dictionary element called 'replicateID'
selectedStrainInfo, which contains a dictionary element called 'replicateID'
I'm looking to check if the replicateID of each of my strains is in a list of selected strains, in python it would be something like this:
for strain in strainInfo:
if strain.replicateID in [selectedStrain.replicateID for selectedStrain in selectedStrainInfo]
print('This strain is selected')
I'm getting the correct functionality in django, but I'm wondering if there's a way to simplify using a list comprehension:
{% for row in strainInfo %}
{% for selectedStrain in selectedStrainsInfo %}
{% if row.replicateID == selectedStrain.replicateID %}
checked
{% endif %}
{% endfor %}
{% endfor %}
List comprehensions are not supported in Jinja
You could pass the data, via Jinja, to JavaScript variables like so
var strainInfo = {{strainInfo|safe}};
var selectedStrainInfo = {{selectedStrainInfo|safe}};
and then do your clean up there.
Use Jinja's safe filter to prevent your data from being HTML-escaped.
Since v2.7 there is selectattr:
Filters a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects with the test succeeding.
If no test is specified, the attribute’s value will be evaluated as a boolean.
Example usage:
{{ users|selectattr("is_active") }}
{{ users|selectattr("email", "none") }}
Similar to a generator comprehension such as:
(u for user in users if user.is_active)
(u for user in users if test_none(user.email))
See docs.

Issues with loops in Django [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
how to create counter loop in django template?
I want to print some data based on some condition,
I want to use it like we used in other languages:
for(i=1;i<=count;i++)
print i
To do this in django I wrote
{% for i in count %}
<p>{{ i }}</p>
{% endfor %}
but it gives me an error 'int' object is not iterable.Count is coming from views.py and if I prints the count alone than it shows the output.
I wanted to print some value until count not becomes zero,So how i can do this in django.
And one more thing can we use while loop in django because i also try to use it for this task but it gives me the error of invalid block tag: 'while'
So please let me know how can I do this task ?
Thanks
Edit
in my view.py I have used like this
count=Product_attributes.objects.count()
and then pass this count to my template
Django templates are not programming language. Write all you logic in the view or models, and pass data into the template:
def view(request):
values = []
for i in range(10):
values.append(i) # your custom logic here
return render_to_response("/path/to/template", {'values': values})
in template:
{% for value in values %}
<p>{{ value }}</p>
{% endfor %}
The "for i in var" syntax works only where "var" is an iterable eg a list, tuple, set, dict...
I'd suggest the following: Instead of passing the item count to the template, pass in the iterable eg list in. If all you have is a count, you can create an iterable using range(count) in the view. In code
# Extract from view
def view(request):
# Set up values. Values is a list / tuple / set of whatever you are counting
values = Product_attributes.objects.all()
return render_to_response("/path/to/template", {'values': values})
# Extract from template
{% for value in values %}
<p>{{value}}</p>
{% endfor %}
The "while" tag is not a valid built in tag in django. A list of valid built-in tags can be seen here: https://docs.djangoproject.com/en/dev/ref/templates/builtins/
This way of doing things is not specific to templates only: it has parallels in "regular python" where the canonical way to iterate over a collection is:
for item in iterable:
# do something with the item
pass
More information on the "python way" of doing for loops can be found here: http://wiki.python.org/moin/ForLoop
If it's not appropriate to add the range to your view code (I don't like adding purely template-ty things to my views), I'd probably create a range filter:
#register.filter
def range(val):
return range(val)
Then you'd use it like this:
{% for i in count|range %}
<p>{{ i }}</p>
{% endfor %}
There's also an extremely ugly hack you can use if you don't want to bother writing any python code for this, it takes advantage of Django's center (or ljust and rjust) filters which create a string of length of the value provided. You can use it like this:
{% for x in count|center:count %}
<p>{{ forloop.counter }}</p>
{% endfor %}
I wouldn't recommend doing it this way though, I'm just demonstrating that it's possible.

In Jinja2 whats the easiest way to set all the keys to be the values of a dictionary?

I've got a dashboard that namespaces the context for each dashboard item. Is there a quick way I can set all the values of a dictionary to the keys in a template?
I want to reuse templates and not always namespace my variables.
My context can be simplified to look something like this:
{
"business": {"businesses": [], "new_promotions": []},
"messages": {"one_to_one": [], "announcements": []
}
So in a with statement I want to set all the business items to be local for the including. To do this currently I have to set each variable individually:
{% with %}
{% set businesses = business["businesses"] %}
{% set new_promotions = business["new_promotions"] %}
{% include "businesses.html" %}
{% endwith %}
I tried:
{% with %}
{% for key, value in my_dict %}
{% set key = value %}
{% endfor %}
{% include "businesses.html" %}
{% endwith %}
But they only have scope in the for loop so aren't scoped in the include...
Long story short: you can't set arbitrary variables in the context. The {% set key = value %} is just setting the variable named key to the given value.
The reason is because Jinja2 compiles templates down to Python code. (If you want to see the code your template generates, download the script at http://ryshcate.leafstorm.us/paste/71c95831ca0f1d5 and pass it your template's filename.) In order to make processing faster, it creates local variables for every variable you use in the template (only looking up the variable in the context the first time it's encountered), as opposed to Django, which uses the context for all variable lookups.
In order to generate this code properly, it needs to be able to track which local or global variables exist at any given time, so it knows when to look up in the context. And setting random variables would prevent this from working, which is why contextfunctions are not allowed to modify the context, just view it.
What I would do, though, is instead of having your business-displaying code be an included template, is have it be a macro in another template. For example, in businesses.html:
{% macro show_businesses(businesses, new_promotions) %}
{# whatever you're displaying... #}
{% endmacro %}
And then in your main template:
{% from "businesses.html" import show_businesses %}
{% show_businesses(**businesses) %}
Or, better yet, separate them into two separate macros - one for businesses, and one for new promotions. You can see a lot of cool template tricks at http://bitbucket.org/plurk/solace/src/tip/solace/templates/, and of course check the Jinja2 documentation at http://jinja.pocoo.org/2/documentation/templates.
I've found a work around - by creating a context function I can render the template and directly set the context or merge the context (not sure thats good practise though).
#jinja2.contextfunction
def render(context, template_name, extra_context, merge=False):
template = jinja_env.get_template(template_name)
# Merge or standalone context?
if merge:
ctx = context.items()
ctx.update(extra_context)
else:
ctx = extra_context
return jinja2.Markup(template.render(ctx))
So my templates look like:
{{ render("businesses.html", business) }}

Categories

Resources