Related
I have a list of events (with links) that I want to show as comma separated like
event1, event2, event3
I tried the solution here but not working for me.
Here is the code :
<p>
{% for element in event.getelement.all() %}
<a href="{{ build_absolute_url(url('main:home_getlink',link.uri)) }}">
{{ element }} </a>
{% endfor %}
</p>
Do:
<p>
{% for element in event.getelement.all %}
<a href="{{ build_absolute_url(url('main:home_getlink',link.uri)) }}">
{{ element }}
</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
Also, what's up with that href? Are you not using named routes whereby you can simply leverage the {% url [route-name] [params] %} tag?
This shouldn't be a function call since it is inside template. Change below,
{% for element in event.getelement.all() %}
with
{% for element in event.getelement.all %}
And for rest, the solution link you've posted should work after that.
Edit:
If you do this,
{{ event.getelement.all|join:", " }}
So this might produce result something like,
GetElement object, GetElement object, GetElement object
to get the value of a specific attribute you have to add the attribute as well. Something like this,
{% for e in event.getelement.all %}
{{ e.<attr_name> }},
{% endfor %}
And this might produce something like,
event1, event2, event3,
Of course this is not an optimal solution because this is not the right way to do things when using any Framework.
Optimal solution:
What should be followed is that, do each and every logic in your views and send clean (pure) form of data to your templates. I mean send lists, dictionaries, objects, tuples should be sent to the templates. Hence creating a list of all the events and sending it templates though context.
Note: Following example is all based on assumptions.
View:
def xyz(request):
event = Event.objects.get(name='xyz')
context = {
'event_elements': [e.name for e in event.getelement.all()]
}
return render(request, 'xyz.html', context)
Template:
{{ event_elements|join:", " }}
Now this will definitely work.
I have some loop on the page and need list item depending from loop number.
When I call:
{{ mylist.1 }}
{{ mylist.2 }}
{{ mylist.3 }}
all works fine but what I really need is something like:
{% for x in somenumber|MyCustomRangeTag %}
{{ mylist.x }}
{% endfor %}
MyCustomRangeTag gives me Python range() it works and I already have x as number. So x is 1, 2, 3 etc. depending from loop number.
Is this possible and how?
This is not possible directly because Django thinks that "x" is the key to lookup in mylist - instead of the value of x. So, when x = 5, Django tries to look up mylist["x"] instead of mylist[5].
Use the following filter as workaround:
#register.filter
def lookup(d, key):
return d[key]
and use it like
{{ mylist|lookup:x }}
The slice tag in Django templates may use python's slicing code, but the syntax is unmistakably different. For instance, if you wanted to get an element of a sequence with a variable, in python you'd write something similar to the following:
>>>mylist = ["0th Element", "1th Element"]
>>>zero, one = 0, 1
>>>mylist[zero]
"0th Element"
>>>mylist[one]
"1th Element"
Using this syntax with the Django slice template tag will return a sliced list in every case, of dubious utility for getting an item of known index:
{% with "0" as zero %}
{% with "1" as one %}
{% with "2" as two %}
{{mylist|slice:zero}} {{mylist|slice:one}} {{mylist|slice:two}}
{% endwith %}
{% endwith %}
{% endwith %}
Renders to the html:
[] ["0th Element"] ["0th Element", "1th Element"]
Note the differences: you are getting the result of mylist[:x] instead of mylist[x].
Django provides enough tools to work around this. The first trick is to use explicit slices like 0:1 for your indices, and then |join:"" the resultant list into a single element. Like so:
{% with "0:1" as zero %}
{{mylist|slice:zero|join:""}}
{% endwith %}
Yields:
0th Element
This comes in particularly handy if you need to access a parent loop's index when dealing with an iterable inside a child loop:
{% for parent in parent_loop %}
{% cycle "0:1" "1:2" "2:3" as parent_loop_index silent %}
{% for child in child_loop %}
{{child|slice:parent_loop_index|join:""}}
{% endfor %}
{% endfor %}
Completed with nothing but stock parts, although I don't think Django has implemented achievements yet.
I notice that #e-satis mentioned it, but I think the built-in slice template tag deserves some love.
{{ item | slice:"2" }} #gets the third element of the list
Are you sure you can't just do:
{% for item in mylist %}
{{ item }}
{% endfor %}
With the slice filter, you can even do some customisation.
Following worked for me
{% for 1,2,3 in mylist %}
# do stuff
Just don't use brackets around 1,2,3
I have some loop on the page and need list item depending from loop number.
When I call:
{{ mylist.1 }}
{{ mylist.2 }}
{{ mylist.3 }}
all works fine but what I really need is something like:
{% for x in somenumber|MyCustomRangeTag %}
{{ mylist.x }}
{% endfor %}
MyCustomRangeTag gives me Python range() it works and I already have x as number. So x is 1, 2, 3 etc. depending from loop number.
Is this possible and how?
This is not possible directly because Django thinks that "x" is the key to lookup in mylist - instead of the value of x. So, when x = 5, Django tries to look up mylist["x"] instead of mylist[5].
Use the following filter as workaround:
#register.filter
def lookup(d, key):
return d[key]
and use it like
{{ mylist|lookup:x }}
The slice tag in Django templates may use python's slicing code, but the syntax is unmistakably different. For instance, if you wanted to get an element of a sequence with a variable, in python you'd write something similar to the following:
>>>mylist = ["0th Element", "1th Element"]
>>>zero, one = 0, 1
>>>mylist[zero]
"0th Element"
>>>mylist[one]
"1th Element"
Using this syntax with the Django slice template tag will return a sliced list in every case, of dubious utility for getting an item of known index:
{% with "0" as zero %}
{% with "1" as one %}
{% with "2" as two %}
{{mylist|slice:zero}} {{mylist|slice:one}} {{mylist|slice:two}}
{% endwith %}
{% endwith %}
{% endwith %}
Renders to the html:
[] ["0th Element"] ["0th Element", "1th Element"]
Note the differences: you are getting the result of mylist[:x] instead of mylist[x].
Django provides enough tools to work around this. The first trick is to use explicit slices like 0:1 for your indices, and then |join:"" the resultant list into a single element. Like so:
{% with "0:1" as zero %}
{{mylist|slice:zero|join:""}}
{% endwith %}
Yields:
0th Element
This comes in particularly handy if you need to access a parent loop's index when dealing with an iterable inside a child loop:
{% for parent in parent_loop %}
{% cycle "0:1" "1:2" "2:3" as parent_loop_index silent %}
{% for child in child_loop %}
{{child|slice:parent_loop_index|join:""}}
{% endfor %}
{% endfor %}
Completed with nothing but stock parts, although I don't think Django has implemented achievements yet.
I notice that #e-satis mentioned it, but I think the built-in slice template tag deserves some love.
{{ item | slice:"2" }} #gets the third element of the list
Are you sure you can't just do:
{% for item in mylist %}
{{ item }}
{% endfor %}
With the slice filter, you can even do some customisation.
Following worked for me
{% for 1,2,3 in mylist %}
# do stuff
Just don't use brackets around 1,2,3
I want to create such loop:
{% for object in objects %}
{% if object.before != object %}
{{ object }} this is different
{% else %}
{{ object }} this is the same
{% endfor %}
Based on https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#for I can't. Is there really no simple way to do this? Or I just need to use counter and check for objects[counter-1]?
P.S. .before is theoretical and objects is simple query list. I want to take and do something with the loop member that encountered before current loop member.
Check ifchanged template tag
There is a "simple way" to do this: write a custom template tag. They're really not hard. This would probably do the trick (untested):
#register.simple_tag
def compare_objects(object_list):
comparisons = []
for i in range(1, len(object_list)):
if object_list[i] > object_list[i-1]:
comparisons.append('bigger')
else:
comparisons.append('smaller')
return comparisons
The built-in template tags and filters don't make it easy (as of Django 1.4), but it is possible by using the with tag to cache variables and the add, slugify, and slice filters to generate a new list with only one member.
The following example creates a new list whose sole member is the previous member of the forloop:
{% for item in list %}
{% if not forloop.first %}
{% with forloop.counter0|add:"-1" as previous %}
{% with previous|slugify|add:":"|add:previous as subset %}
{% with list|slice:subset as sublist %}
<p>Current item: {{ item }}</p>
<p>Previous item: {{ sublist.0 }}</p>
{% endwith %}
{% endwith %}
{% endwith %}
{% endif %}
{% endfor %}
This isn't an elegant solution, but the django template system has two faults that make this hack unavoidable for those who don't what to write custom tags:
Django template syntax does not allow nested curly parenthesis. Otherwise, we could do this:
{{ list.{{ forloop.counter|add:-1 }} }}
The lookup operator does not accept values stored using with (and perhaps for good reason)
{% with forloop.counter|add:-1 as index %}
{{ list.index }}
{% endwith %}
This code should work just fine as a django template, as long as object has a property or no-argument method called before, and objects is iterable (and '<' is defined).
{% for object in objects %}
{% if object.before < object %}
this is bigger
{% else %}
this is smaller
{% endfor %}
How do I write a numeric for loop in a Django template? I mean something like
for i = 1 to n
I've used a simple technique that works nicely for small cases with no special tags and no additional context. Sometimes this comes in handy
{% for i in '0123456789'|make_list %}
{{ forloop.counter }}
{% endfor %}
{% with ''|center:n as range %}
{% for _ in range %}
{{ forloop.counter }}
{% endfor %}
{% endwith %}
Unfortunately, that's not supported in the Django template language. There are a couple of suggestions, but they seem a little complex. I would just put a variable in the context:
...
render_to_response('foo.html', {..., 'range': range(10), ...}, ...)
...
and in the template:
{% for i in range %}
...
{% endfor %}
My take on this issue, i think is the most pythonic. Create a my_filters.py in your apps templatetags directory.
#register.filter(name='times')
def times(number):
return range(number)
Usage in your template:
{% load my_filters %}
{% for i in 15|times %}
<li>Item</li>
{% endfor %}
You can pass a binding of
{'n' : range(n) }
to the template, then do
{% for i in n %}
...
{% endfor %}
Note that you'll get 0-based behavior (0, 1, ... n-1).
(Updated for Python3 compatibility)
Maybe like this?
{% for i in "x"|rjust:"100" %}
...
{% endfor %}
I'm just taking the popular answer a bit further and making it more robust. This lets you specify any start point, so 0 or 1 for example. It also uses python's range feature where the end is one less so it can be used directly with list lengths for example.
#register.filter(name='range')
def filter_range(start, end):
return range(start, end)
Then in your template just include the above template tag file and use the following:
{% load myapp_filters %}
{% for c in 1|range:6 %}
{{ c }}
{% endfor %}
Now you can do 1-6 instead of just 0-6 or hard coding it. Adding a step would require a template tag, this should cover more uses cases so it's a step forward.
You can pass :
{ 'n' : range(n) }
To use template :
{% for i in n %}
...
{% endfor %}
I tried very hard on this question, and I find the best answer here:
(from how to loop 7 times in the django templates)
You can even access the idx!
views.py:
context['loop_times'] = range(1, 8)
html:
{% for i in loop_times %}
<option value={{ i }}>{{ i }}</option>
{% endfor %}
You don't pass n itself, but rather range(n) [the list of integers from 0 to n-1 included], from your view to your template, and in the latter you do {% for i in therange %} (if you absolutely insist on 1-based rather than the normal 0-based index you can use forloop.counter in the loop's body;-).
Just incase anyone else comes across this question… I've created a template tag which lets you create a range(...): http://www.djangosnippets.org/snippets/1926/
Accepts the same arguments as the 'range' builtin and creates a list containing
the result of 'range'.
Syntax:
{% mkrange [start,] stop[, step] as context_name %}
For example:
{% mkrange 5 10 2 as some_range %}
{% for i in some_range %}
{{ i }}: Something I want to repeat\n
{% endfor %}
Produces:
5: Something I want to repeat
7: Something I want to repeat
9: Something I want to repeat
You should use "slice" in template, a example like this:
in views.py
contexts = {
'ALL_STORES': Store.objects.all(),
}
return render_to_response('store_list.html', contexts, RequestContext(request, processors=[custom_processor]))
in store_list.html:
<ul>
{% for store in ALL_STORES|slice:":10" %}
<li class="store_item">{{ store.name }}</li>
{% endfor %}
</ul>
This method supports all the functionality of the standard range([start,] stop[, step]) function
<app>/templatetags/range.py
from django import template
register = template.Library()
#register.filter(name='range')
def _range(_min, args=None):
_max, _step = None, None
if args:
if not isinstance(args, int):
_max, _step = map(int, args.split(','))
else:
_max = args
args = filter(None, (_min, _max, _step))
return range(*args)
Usage:
{% load range %}
<p>stop 5
{% for value in 5|range %}
{{ value }}
{% endfor %}
</p>
<p>start 5 stop 10
{% for value in 5|range:10 %}
{{ value }}
{% endfor %}
</p>
<p>start 5 stop 10 step 2
{% for value in 5|range:"10,2" %}
{{ value }}
{% endfor %}
</p>
Output
<p>stop 5
0 1 2 3 4
</p>
<p>start 5 stop 10
5 6 7 8 9
</p>
<p>start 5 stop 10 step 2
5 7 9
</p>
This essentially requires a range function. A Django feature ticket was raised (https://code.djangoproject.com/ticket/13088) for this but closed as "won't fix" with the following comment.
My impression of this idea is that it is trying to lead to programming in the template. If you have a list of options that need to be rendered, they should be computed in the view, not in the template. If that's as simple as a range of values, then so be it.
They have a good point - Templates are supposed to be very simple representations of the view. You should create the limited required data in the view and pass to the template in the context.
{% for _ in ''|center:13 %}
{{ forloop.counter }}
{% endfor %}
If the number is coming from a model, I found this to be a nice patch to the model:
def iterableQuantity(self):
return range(self.quantity)
You can use:
{% with ''|center: i as range %}
For those who are looking to simple answer, just needing to display an amount of values, let say 3 from 100 posts for example just add {% for post in posts|slice:"3" %} and loop it normally and only 3 posts will be added.
This shows 1 to 20 numbers:
{% for i in "x"|rjust:"20"|make_list %}
{{ forloop.counter }}
{% endfor %}
also this can help you:
(count_all_slider_objects come from views)
{% for i in "x"|rjust:count_all_slider_objects %}
{{ forloop.counter }}
{% endfor %}
or
{% with counter=count_all_slider_objects %}
{% if list_all_slider_objects %}
{% for slide in list_all_slider_objects %}
{{forloop.counter|add:"-1"}}
{% endfor%}
{% endif %}
{% endwith %}
You can pass range(n) instead of n in the context in views.py. This will give you an iterable list.
context['range']= range(n)
Then you can iterate in your template this way:
{% for i in range %}
<!-- your code -->
{% endfor %}
{% for i in range(10) %}
{{ i }}
{% endfor %}