80

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?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
cleg
  • 4,862
  • 5
  • 35
  • 52

5 Answers5

96

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

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 140
    Very sad. I'd like to have a simplier way. – cleg Mar 18 '10 at 17:16
  • 3
    I think the solution with the builtin python `@property` is the better solution, of course, depending on the situation. – jrast May 04 '14 at 11:02
  • 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) – matts1 Dec 17 '14 at 04:48
  • 5
    This sadness is exactly why I love React JSX. – Andy Oct 25 '16 at 18:48
  • 1
    @Andy 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) – nuts Apr 17 '20 at 08:50
  • @nuts 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. – Andy Apr 18 '20 at 18:41
  • In fact people have explored this exact idea: https://github.com/michaeljones/packed – Andy Apr 18 '20 at 18:43
  • Some people render React JSX serverside via PyV8 apparently: https://github.com/nitely/python-react-v8 – Andy Apr 18 '20 at 18:46
  • 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 toolset – Andy Apr 18 '20 at 18:47
  • Well, see. Thank you, that is more helpful information underlining your point than just calling something a sadness and being done with it. – nuts Apr 18 '20 at 19:43
  • See example here: https://stackoverflow.com/questions/28513528/passing-arguments-to-model-methods-in-django-templates – Rufat Mar 24 '23 at 02:15
29

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 %>
sherpya
  • 4,890
  • 2
  • 34
  • 50
12

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.

Marcin
  • 48,559
  • 18
  • 128
  • 201
12

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

Why don't you pass to Django template the variable storing function's return value, instead of the function?


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.

You should set variables in Django views instead of templates, and then pass them to the template.

dolma33
  • 4,133
  • 6
  • 28
  • 48
  • This function returns some records, and parameter is their count. I'd like to control this value from template. – cleg Mar 26 '10 at 21:31
  • 3
    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.. – Rob Jul 26 '11 at 13:50
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>
sidmanu
  • 31
  • 1
  • 3
  • 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. – Saad Saadi May 30 '17 at 07:37