Issues with loops in Django [duplicate] - python

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.

Related

How do I obfuscate data in variables in jinja2? e.g. variable = "John Smith", I want something like "Odsv Wgtvs"

So I am trying to create a page where details are only shown to users who are logged in. I am able to change the content statically using
{% if user.is_authenticated %}
So I can replace something like {{ celebrity.name }} with Dummy Name, but then every occurrence of this is the same.
I'm hoping there is an easy way to mess with celebrity.name to obfuscate the actual data.
If there is no easy way I'll happily write my own function, but at this point I'm not sure if I should be writing it in jinja2 in the html template or if I should do it in views.py so would appreciate some guidance.
You could write your own custom template filter:
from django import template
register = template.Library()
#register.filter
def obfuscate(value, user):
if user.is_authenticated():
return value
# do something before returning
return '#SECRET#' + value + '#SECRET#'
This could be user in the template:
{{ celebrity.name|obfuscate:user }}
If the obfuscation has to be deterministic (same values always yield the same obfuscated result) you could use a hash function (will return giberrish, not real names), or a fixed dictionary which you use to subsitute names, or something else.
If the replacement can be non-deterministic, you could use some random char replacements.
Use set
{% if user.is_authenticated %}
{% set celebrity_name = celebrity.name %}
{% else %}
{% set celebrity_name = "dummy" %}
Or do you want to have unique dummy values..? You could assign anything from Python to celebrity_name if you want to use different values.

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.

Accessing a specific dictionary inside a dictionary - Django Templates

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.

Sorting and indexing into a list in a Django template?

How can you perform complex sorting on an object before passing it to the template? For example, here is my view:
#login_required
def overview(request):
physicians = PhysicianGroup.objects.get(pk=physician_group).physicians
for physician in physicians.all():
physician.service_patients.order_by('bed__room__unit', 'bed__room__order', 'bed__order')
return render_to_response('hospitalists/overview.html', RequestContext(request, {'physicians': physicians,}))
The physicians object is not ordered correctly in the template. Why not?
Additionally, how do you index into a list inside the template? For example, (this doesn't work):
{% for note_type in note_types %}
<div><h3>{{ note_type }}</h3>
{% for notes in note_sets.index(parent.forloop.counter0) %}
#only want to display the notes of this note_type!
{% for note in notes %}
<p>{{ note }}</p>
{% endfor %}
{% endfor %}
</div>
{% endfor %}
Thanks a bunch, Pete
As others have indicated, both of your problems are best solved outside the template -- either in the models, or in the view. One strategy would be to add helper methods to the relevant classes.
Getting a sorted list of a physician's patients:
class Physician(Model):
...
def sorted_patients(self):
return self.patients.order_by('bed__room__unit',
'bed__room__order',
'bed__order')
And in the template, use physician.sorted_patients rather than physician.patients.
For the "display the notes of this note_type", it sounds like you might want a notes method for the note_type class. From your description I'm not sure if this is a model class or not, but the principle is the same:
class NoteType:
...
def notes(self):
return <calculate note set>
And then the template:
{% for note_type in note_types %}
<div><h3>{{ note_type }}</h3></div>
{% for note in note_type.notes %}
<p>{{ note }}</p>
{% endfor %}
</div>
{% endfor %}
"I'd like to do this from within a template:"
Don't. Do it in the view function where it belongs.
Since the question is incomplete, it's impossible to guess at the data model and provide the exact solution.
results= physician.patients.order_by('bed__room__unit', 'bed__room__order', 'bed__order')
Should be sufficient. Provide results to the template for rendering. It's in the proper order.
If this isn't sorting properly (perhaps because of some model subtletly) then you always have this kind of alternative.
def by_unit_room_bed( patient ):
return patient.bed.room.unit, patient.bed.room.order, patient.bed.order
patient_list = list( physician.patients )
patient_list.sort( key=by_unit_room_bed )
Provide patient_list to the template for rendering. It's in the proper order.
"how do you index into a list inside the template"
I'm not sure what you're trying to do, but most of the time, the answer is "Don't". Do it in the view function.
The template just iterate through simple lists filling in simple HTML templates.
If it seems too complex for a template, it is. Keep the template simple -- it's only presentation. The processing goes in the view function
You should be able to construct the ordered query set in your view and pass it to your template:
def myview(request):
patients = Physician.patients.order_by('bed__room__unit',
'bed__room__order',
'bed__order')
return render_to_response('some_template.html',
dict(patients=patients),
mimetype='text/html')
Your template can then loop over patients which will contain the ordered results. Does this not work for you?
EDIT: For indexing, just use the dot syntax: mylist.3 in a template becomes mylist[3] in python. See http://docs.djangoproject.com/en/dev/ref/templates/api/#rendering-a-context for more information.
This is one way of doing it, although very ugly :
{% for note in note_sets|slice:"forloop.counter0"|first %}

Categories

Resources