Django filter: dynamic slice - django

I am refering to this slice filter: https://docs.djangoproject.com/en/dev/ref/templates/builtins/#slice
if I have this list a=[1, 2, 3, 4, 5], is there any way to take the first half of this list?
Something like {{ a|slice:":3" }}.
But instead of 3 I want the size of list a. And a can have even or odd number of elements. And I don't want to pass the list length as a variable in the context from the view
later EDIT
I was wondering if there is another solution, other than a custom filter

If used in a for-loop, you can do this:
{% for item in a %}
{% if forloop.counter < forloop.revcounter %}
{# first half of list #}
{% else %}
{# second half of list #}
{% endif %}
{% endfor %}

You can do custom filter for this purpose:
#register.filter("half_slice")
def half_slice_filter(value):
return value[:len(value)/2]

Related

Put items on top in django template for loop

The model has a field named "is_highlighted", i want to put all items on top if is_highlighted == True when iterate thru the object list.
You can give 2 for loops to do this. In first for loop check the condition true.
{% for x in list %}
{% if x.is_highlighted == True %}
....
..
{% endif %}
{% endfor %}
display others in second for loop
{% for x in list %}
{% if x.is_highlighted != True %}
...
...
You can also pass 2 query sets through context. I don't know if it's best or any other way. simply this will work.

Accessing nested list by variable in Django templates [duplicate]

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

Skip the first element in list

Is it possible with django template tags to skip the first element in a list when doing the for loop? For example I want to begin from element 1 instead from 0.
builtin slice filter
{{ qs|slice:"1:" }}
You can e.g. do:
{% if not forloop.first %}
...
{% endif %}

Adding defaults to column headers in django

I have a script which imports data in tables from other websites. The tables are between 5 and 15 columns wide and arbitrarily long.
After I've got the raw data I want the opportunity to make sure my guesses about the column headers are correct. So I want to have a at the top with a list of the 15 things a column could be called. That way I can quickly correct any poor decisions made by my automatic code.
So the auto code generates 2 arrays, the first of strings:
possible_headers = ["one", "two", "three"...]
The second of indexes into that first array
likely_headers = [2, 0, 5...]
(the columns headers would be "three" then "one" then "six")
And use them like this in my template:
{% for likely_head in likely_headers %}
<th>
<select name="colHeader">
{% for poss_head in possible_headers %}
{% if forloop.counter0 == likely_headers.forloop.parentloop.counter0 %}
<option value="Col:{{forloop.counter0}}" selected>{{poss_head}}</option>
{% else %}
<option value="Col:{{forloop.counter0}}">{{poss_head}}</option>
{% endif %}
{% endfor %}
</select>
</th>
{% endfor %}
With the idea that the likely header will be the selected/default item in the select input. Problem is the:
likely_headers.forloop.parentloop.counter0
Doesn't evaluate. forloop.parentloop.counter0 works correctly but apparently it cannot be used as an index into a list.
I'm new to django so I'm probably doing it all wrong, please be nice!
I don't see why you're using likely_headers.forloop.parentloop.counter0 when you should use forloop.parentloop.counter0 according to docs https://docs.djangoproject.com/en/dev/ref/templates/builtins/#for
You may also try solving it by encapsulating counter with {% with %} tag
{% for likely_head in likely_headers %}
{% with forloop.counter0 as parent_counter %}
{% for poss_head in possible_headers %}
{{ parent_counter }}
{% endfor %}
{% endwith %}
{% endfor %}
I haven't checked that it works for sure but I think it should.
Also you're probably trying to solve problem that should not be solved in templates. You can try using tags, processing headers in view (using library?) and just returning list of headers that should be rendered.
The list of integers I thought I had was in truth a list of strings ["1", "5", "3"] so they failed comparison to the for loop iterator. Creating a real list of ints solved the problem.

Get list item dynamically in django templates

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