How to call a function that takes an argument in a Django template?
Asked Answered
J

6

86

I'm passing to Django's template a function, which returns some records. I want to call this function and iterate over its result.

{% for item in my_func(10) %} 

That doesn't work. I've tried to set the function's return value to a variable and iterate over the variable, but there seems to be no way to set a variable in a Django template.

Is there any normal way to do it?

Jeanelle answered 18/3, 2010 at 9:53 Comment(0)
U
100

You cannot call a function that requires arguments in a template. Write a template tag or filter instead.

Underbrush answered 18/3, 2010 at 9:58 Comment(11)
Very sad. I'd like to have a simplier way.Jeanelle
I think the solution with the builtin python @property is the better solution, of course, depending on the situation.Physique
yes, however that doesn't solve the problem. Django automatically calls functions if they require no arguments. Writing {% for item in myfunc %} is equivalent to for item in myfunc() if myfunc is a function with no arguments. The only real restriction with django is calling a function which requires arguments, which @property doesn't solve (although admittedly you could set some attributes in the template and use them as arguments, but that isn't particularly clean either)Billiton
This sadness is exactly why I love React JSX.Catalano
@Catalano how is that a constructive and helpful comment?... And you're comparing apples and elefants; or how do you call a Django-internal function from within React? (I assume you use an API but then this is not at all the scope of this question anymore)Insomnolence
@Insomnolence to elaborate, if cleg and everyone who upvoted his comment are sad and want a simpler way to do things like this in templates, they could take inspiration from React and build a similar templating system for Python/Django with a transpiler that transpiles virtual DOM elements embedded in Python code into Python function calls, and then they would be able to embed arbitrary Python expressions in their templates without arbitrary limitations like this question demonstrates.Catalano
In fact people have explored this exact idea: github.com/michaeljones/packedCatalano
Some people render React JSX serverside via PyV8 apparently: github.com/nitely/python-react-v8Catalano
It's worth knowing if other API designs don't have the weaknesses of the one you're dealing with, even if there's currently no such API available for your toolsetCatalano
Well, see. Thank you, that is more helpful information underlining your point than just calling something a sadness and being done with it.Insomnolence
See example here: #28514028Frederico
F
30

if you have an object you can define it as @property so you can get results without a call, e.g.

class Item:
    @property
    def results(self):
        return something

then in the template:

<% for result in item.results %>
...
<% endfor %>
Filariasis answered 3/2, 2014 at 15:11 Comment(5)
Do you have a reference for this @sherpya?Utmost
python built-in property docs.python.org/2/library/functions.html#propertyFilariasis
Not the same. The things in the array can be different classes of items.Combinative
The @property doesn't change anything with respect to calling methods within the template. You can remove it and the template example will still work exactly the same. Django already allows calling methods with no arguments.Procreant
@TimTisdall not at the time of the replyFilariasis
T
15

By design, Django templates cannot call into arbitrary Python code. This is a security and safety feature for environments where designers write templates, and it also prevents business logic migrating into templates.

If you want to do this, you can switch to using Jinja2 templates (http://jinja.pocoo.org/docs/), or any other templating system you like that supports this. No other part of django will be affected by the templates you use, because it is intentionally a one-way process. You could even use many different template systems in the same project if you wanted.

Tartary answered 27/7, 2013 at 21:14 Comment(0)
F
13

I'm passing to Django's template a function, which returns me some records

Instead of passing the function, you can pass to the variable storing the function's return value.


I've tried to set fuction's return value to a variable and iterate over variable, but there seems to be no way to set variable in Django template.

Instead of setting variables in Django templates, set them in Django views and pass them to the template.

Franconia answered 25/3, 2010 at 21:46 Comment(2)
This function returns some records, and parameter is their count. I'd like to control this value from template.Jeanelle
What if you want the function to be evaluated lazily? e.g. you want the result to be available if required, but you don't want to calculate it for nothing? I guess I'm stuck writing template tags..Blackfoot
S
3

What you could do is, create the "function" as another template file and then include that file passing the parameters to it.

Inside index.html

<h3> Latest Songs </h3>
{% include "song_player_list.html" with songs=latest_songs %}

Inside song_player_list.html

<ul>
{%  for song in songs %}
<li>
<div id='songtile'>
<a href='/songs/download/{{song.id}}/'><i class='fa fa-cloud-download'></i>&nbsp;Download</a>

</div>
</li>
{% endfor %}
</ul>
Scholarship answered 17/1, 2015 at 17:39 Comment(1)
How can i control that {% include "song_player_list.html" with songs=latest_songs %} execute only when a button is clicked. I tried to put it in a function but Django template execute it everytime i load the page.Gunning
P
0

create a custom template filter (source)

app_name/templatetags/app_name_tags.py:

from django import template
register = template.Library()
@register.filter
def my_func(num):
    return [i for i in range(num)] # for example

html file:

{% load app_name_tags %}
{% for item in 10|my_func %}
    {{item}}...
{% endfor %}
Positivism answered 24/4 at 17:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.