Django loop variable as key - python

i am new to django and tried to use the variable of an loop as a key for another object:
this is my views.py
...
files = Files.objects.filter(dataset__id = instance.dataset.id)
context = {'files': files, 'range': range(files.count())}
return render_to_response("test.html", context, context_instance=RequestContext(request))
and my test.html looks like this:
{% for i in range %}
<img title="{{i}}" src="{{files.i.data_files.url}}"/>
{% endfor %}
if i use files.0.data_files.url (or 1,2,3..) instead of files.i. it works, but i want to give out all images and also need the position of the image.
can you help me please?

the thing you're probably looking for is a magic variable {{ forloop.counter }} (or {{ forloop.counter0 }} if you want to use zero-based index) available inside {% for %} loop:
{% for file in files %}
<img title="{{ forloop.counter }}" src="{{file.data_files.url}}"/>
{% endfor %}

Related

Tag inside tag Django template

First of all, let me show our views.py file.
context = {
'id' : id,
'durum' : durum,
'range': range(len(id)),
}
I have such data in template;
context.id = [12, 10, 10]
context.durum = ['UPL','PPL','FIUPL']
I want to match this data like this;
12 UPL
10 PPL
10 FIUPL
I created a for loop for this, but need to edit
{% for i in context.range %}
{{ context.id }}
{{ context.durum }}
{% endfor %}
Like this;
{% for i in context.range %}
{{ context.id.i }}
{{ context.durum.i }}
{% endfor %}
But I can't use the variable i in the loop.
Use zip in view
Ex:
context = {
'data' : zip(id, durum)
}
And then in template
Use:
{% for id, durum in data %}
{{ id }}
{{ durum }}
{% endfor %}
You can use list comprehension.
So, for example:
my_list = list(zip(context['id'], context['durum'], context['range']))
And then in the template, you can use:
{% for item in my_list %}
{{ item.0 }} -- { item.1 }}
{% endfor %}
Well, it seems like you moved to python from some other language. You don't usually use indexing in python for loops (they are much easier and more intuitive) that's why it was hard for you to 'pair' those values. If you still can refactor your code, instead of making to list with attributes on matching indexes use a dict. One - it will let you unpack really easily in django template
{% for id, durum in my_dict %}
{{ id }} {{ durum }}
{% endfor %}
Two - it will prevent any errors connected with wrong index because you just call id and it will get the right durum. Three - it will be very easy to update such data set.
my_dict.update({new_id: new_durum})
Please consider spending a little bit of time learning new stuff because it will make your python experience much more pleasureable. Oh and btw - most of time you dont have to specify the {{ context.something }} call - its enough to call {{ something }}

adding an integer postfix or prefix to an html attribute with flask-wtforms

I have the following thing in a jinja2 for loop:
{{ meal[item]['open-modal'].submit(**{ 'class':'btn btn-primary',
'data-toggle':'modal',
'data-target':'#myModal' }) }}
I need to have an index on the data-target like:
{{ meal[item]['open-modal'].submit(**{ 'class':'btn btn-primary',
'data-toggle':'modal',
'data-target':'#myModal-item' }) }}
item is the index needed in this case. Is there a way to escape item out of this "ad-hoc dictionary"? So that it takes on the same values as in meal[item]?
I need the 'data-target' attribute to render as '#myModal-0', '#myModal-1', etc.. As it stands each 'data-target' attribute gets set as '#myModal-item' for each item in the loop. In other words it sets item in the second line of code as a string.
In case it is ever helpful for someone, what wound up solving my problem was:
<form method="POST">
{{ meal[item]['open-modal'].csrf_token }}
{{ meal[item]['open-modal'].submit( **{ 'class':'btn btn-primary',
'data-toggle':'modal',
'data-target':'#myModal-' +
item|string } ) }}
</form>
Keep in mind that this is nested inside of two for loops in jinja2.
{% for meal in menu_dict %}
{% for item in meal %}
....
{% endfor %}
{% endfor %}
The point is summarized with this, basically:
'data-target':'#myModal-' + item|string
adds the postfix.

Modify django templates to check for values in a dict

I have the following Django template.
{% load custom_tags %}
<ul>
{% for key, value in value.items %}
<li> {{ key }}: {{ value }}</li>
{% endfor %}
I need to check for the value and do some modifications.
If the value is True , instead of value I have to print Applied , else if it False I need to print Not Applied.
How to achieve that?
Very simple if-else clause here. Take a look at the django template docs to familiarize yourself with some of the common tags.
{% if value %}
APPLIED
{% else %}
NOT APPLIED
{% endif %}
You asked how to do this as a filter... I'm not sure why, but here is it:
In your app's templatetags directory create a file called my_tags.py or something and make the contents
from django import template
register = template.Library()
#register.filter
def applied(value):
if value:
return 'Applied'
else:
return 'Not applied'
Then in your template make sure to have {% load my_tags %} and use the filter with {{ value|applied }}

Django use value of template variable as part of another variable name

I currently have this for loop inside my template:
{% for i in 1234|make_list %}
I would like to obtain something like this inside loop:
{{ form.answer_{{ i }} }}
I am aware that the above line is not valid (it raises TemplateSyntaxError), but I would like to know if there is any way to use the value of i as part my other variable name.
First, you would need a custom template filter to mimic getattr() functionality, see:
Performing a getattr() style lookup in a django template
Then, you would need add template filter for string concatenation:
{% load getattribute %}
{% for i in 1234|make_list %}
{% with "answer_"|add:i as answer %}
{{ form|getattribute:answer }}
{% endwith %}
{% endfor %}

create templates on the fly / dynamically

I am currently writing a django app around a rather complex data model.
For many use cases, I need to build similar, but slightly differing templates (incl. graphviz etc..).
Now I wonder if there is a way to follow DRY and create the templates "on the fly", e.g. based on a nested tuple (of which one gets defined per use-case -> template).
Practically speaking I'd like to stop writing these:
static_template_case1.html
{% if program %}
{{ program.name }}
{% for process in program.process_set.all %}
{{ process.name }}
{% for step in process.step_set.all %}
{{ step.name }}
{% endfor %}
{% for control in process.control_set.all %}
{{ control.name }}
{% endfor %}
{% endfor %}
{% endif %}
and replace it with something in the following direction:
template_generator.py
structure_case1 = ("program"("process"("step","control")))
def onTheFlyTemplate(structure):
# iterate through structure
# build template dynamically
# return template
onTheFlyTemplate(structure_case1)
I was not able to find something similar and also don't know yet where to start generating templates on the fly, nor how to integrate it.
Within the views feels like a good starting point, (instead of loader.get_template('static_template_case1.html')).
Thanks for any hint sending me into the right direction as well as your thoughts if DRY is being "overdone" here.
Ralph
Edit
I got a step closer, doing the following:
In the view:
from django.template import Template
def templateGen():
return Template("Program: {{program.count}}")
#login_required
def test(request):
program = Program.objects.all()
t = templateGen()
c = RequestContext(request,locals())
return HttpResponse(t.render(c))
So far this is only a proof of concept. The real work will be to write a smart "templateGen()" listening to the nested tuple.
How about an inclusion tag?
#register.inclusion_tag('<your-template.html>')
def get_program(program_id):
return {'program': <some logic to return your Program object>}
Your main template:
{%load my-template-tags%}
<div id="my-div">
{%get_program program_id %}
</div>
And your template file:
{{ program.name }}
{% for process in program.process_set.all %}
{{ process.name }}
{% for step in process.step_set.all %}
{{ step.name }}
{% endfor %}
{% for control in process.control_set.all %}
{{ control.name }}
{% endfor %}
{% endfor %}
You'd have to pass in your program_id to the main template.

Categories

Resources