# Support a new \`{% set %}\` tag and defining dicts, list, sets and tuples in \`{% with %}\` and \`{% set %}\`

**URL:** <https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787>\
**Category:** Django Internals\
**Created:** [October 19, 2024, 9:51am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787 "2024-10-19T09:51:15Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![christophehenry](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/christophehenry/32/14888_2.png) [@christophehenry](https://forum.djangoproject.com/u/christophehenry)\
**Post date:** [October 19, 2024, 9:51am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/1 "2024-10-19T09:51:16Z")

</div>

_Edit_: I change the title of this thread to reduce the scope of the discussion.

Following [this discussion](https://forum.djangoproject.com/t/add-withdict-and-withlist-tags-to-allow-creating-dicts-and-lists-in-templates/35658/1), @adamchainz suggested to open a discussion about adding a `{% set %}` tag supporting [Jinja’s](https://jinja.palletsprojects.com/en/3.1.x/templates/#assignments) assignments.

In particular, I’d love to create inline sequences like this first example:

```django
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}

```

Also, shoud it enable calling arbitrary functions and not just filters with zero or 1 argument?

```django
{% set ns = namespace(found=false) %}

```

I would really love that too because I often found myself limited by DTL’s filter engine. And limiting this feature to only the `{% set %}` tag could be a way to experiment on evolving DTL’s syntax in a limited scope.

I would definitely work on that.

---

<div class="post-metadata">

**Author:** ![carltongibson](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/carltongibson/32/267_2.png) [@carltongibson](https://forum.djangoproject.com/u/carltongibson)\
**Post date:** [October 19, 2024, 10:03am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/2 "2024-10-19T10:03:00Z")

</div>

@adamchainz Can I ask you to clarify exactly what you have in mind here?

Calling arbitrary Python functions in templates would be… erm… _something of a departure_, shall we say, so I can’t think you’d mean that. (Maybe you do? 😳)

The DTL’s approach here is _write a custom tag_. (Some kind of helpers to make writing custom tags that update the context easier, I could get behind, if we need those.)

---

<div class="post-metadata">

**Author:** ![christophehenry](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/christophehenry/32/14888_2.png) [@christophehenry](https://forum.djangoproject.com/u/christophehenry)\
**Post date:** [October 19, 2024, 10:19am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/3 "2024-10-19T10:19:10Z")

</div>

> [@carltongibson](#):
>
> Calling arbitrary Python functions in templates would be… erm… _something of a departure_, shall we say, so I can’t think you’d mean that. (Maybe you do? 😳)

Maybe I didn’t understand @adamchainz correctly but if I did, limiting this to `{% set %}` is the perfect first setp. Let’s try it and see how the community greets the feature without breaking the rest of DTL.

> [@carltongibson](#):
>
> The DTL’s approach here is _write a custom tag_. (Some kind of helpers to make writing custom tags that update the context easier, I could get behind, if we need those.)

Well I think that’s a problem. I feel that approach is often getting in my way more often that it helps me. Sometimes, `@simple_tag` is not enough and writing a tag for a feature that will be used only once or twice in the whole project is kind of a burden, IMHO.

---

<div class="post-metadata">

**Author:** ![carltongibson](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/carltongibson/32/267_2.png) [@carltongibson](https://forum.djangoproject.com/u/carltongibson)\
**Post date:** [October 19, 2024, 10:38am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/4 "2024-10-19T10:38:01Z")

</div>

Sure, I understand you want the DTL to be more like Jinja… _Just use Jinja_ is answer there.

Keeping Python out of the template is precisely the reason to use the DTL — that’s its strength. Folks coming Jinja often are adverse to defining custom tags, but it’s something to lean into. They’re easy enough to write (once you get past the first library setup) and it means you end up with an encapsulated, testable units of code — it makes your code better. (That’s the _Why **not** Jinja_.)

What I’d like to see here is what @adamchainz’s actual idea here is.

---

<div class="post-metadata">

**Author:** ![boxed](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/boxed/32/11975_2.png) [@boxed](https://forum.djangoproject.com/u/boxed)\
**Post date:** [October 19, 2024, 1:23pm UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/5 "2024-10-19T13:23:33Z")

</div>

> [@carltongibson](#):
>
> They’re easy enough to write (once you get past the first library setup) and it means you end up with an encapsulated, testable units of code — it makes your code better. (

Sometimes yes. But far from always. For example, that to multiply you have to write a filter and instead of `{{ foo * 4 }}` write `{{ foo|multiply_by:4 }}` that doesn’t improve the code.

I personally find that the easiest path with DTL is almost always to add methods to the models, since you can call them (assuming no arguments!), which pollutes my models with single use code, which makes the view more coupled to the rest of the code base, and works against code isolation. Writing template tags is a no go in this situation as you can’t have template tags per view.

If I can pass functions into the context and call them in `{% set %}`, and I can do basic python math, that would be helped a lot I think.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [October 19, 2024, 2:39pm UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/6 "2024-10-19T14:39:47Z")

</div>

I am one of those remaining adamently opposed to arbitrary extensions of the DTL.

If you need Jinja-like functionality, use Jinja. It’s there for precisely that reason.

For more details about _why_ I hold this opinion, see [Django design philosophies DTL - confirm if should update - #9 by KenWhitesell](https://forum.djangoproject.com/t/django-design-philosophies-dtl-confirm-if-should-update/27363/9)

---

<div class="post-metadata">

**Author:** ![christophehenry](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/christophehenry/32/14888_2.png) [@christophehenry](https://forum.djangoproject.com/u/christophehenry)\
**Post date:** [October 19, 2024, 3:02pm UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/7 "2024-10-19T15:02:29Z")

</div>

> [@carltongibson](#):
>
> Sure, I understand you want the DTL to be more like Jinja… _Just use Jinja_ is answer there.

> [@KenWhitesell](#):
>
> If you need Jinja-like functionality, use Jinja. It’s there for precisely that reason.

I’m sorry, I really don’t want the discussion to heat up. But i don’t feel like replying to:

> I’d like a few features from Jinja that I find would really make the language easier

with

> Just use that other language that has a really different syntax and ecosystem and rewrite your existing project with that (or alternatively adopt 2 different templating systems in your project)

sounds like an appropriate answer to user’s requests.

There must be a middle ground here, right?

---

<div class="post-metadata">

**Author:** ![carltongibson](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/carltongibson/32/267_2.png) [@carltongibson](https://forum.djangoproject.com/u/carltongibson)\
**Post date:** [October 19, 2024, 4:37pm UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/8 "2024-10-19T16:37:12Z")

</div>

Hey @christophehenry,

Template languages are ten-a-penny. Along with twitter clients and static site generators, writing your own was once a right of passage.

Despite the choice of syntax — moustaches obviously my favourite — they fall into two camps: those that allow evaluation of expressions from the hosting language and those that don’t. (Both have advantages and disadvantages.) Jinja falls into one, the Django Template Language into the other. If you **want** such evaluation _Just use Jinja_ is literally, calmly, dispassionately the correct answer. To add such to the DTL is to change the _kind of thing_ it is.

(This keeps coming up, so I guess I might have to blog about it.)

> [@christophehenry](#):
>
> There must be a middle ground here, right?

Yes, entirely. That’s what I was asking for in my initial reply:

> [@carltongibson](#):
>
> The DTL’s approach here is _write a custom tag_. (Some kind of helpers to make writing custom tags that update the context easier, I could get behind, if we need those.)

---

<div class="post-metadata">

**Author:** ![boxed](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/boxed/32/11975_2.png) [@boxed](https://forum.djangoproject.com/u/boxed)\
**Post date:** [October 19, 2024, 7:04pm UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/9 "2024-10-19T19:04:02Z")

</div>

> [@carltongibson](#):
>
> If you **want** such evaluation _Just use Jinja_ is literally, calmly, dispassionately the correct answer.

I find the word “just” here to be doing way too much work. It’s not “just” at all. It’s a big deal in fact. Jinja is incompatible in many ways, so it’s not at all simple to switch, and if you try, you don’t in fact end up switching, but _adding_ a template language, if you for example use the Django admin, or use any third party apps that use templates.

---

<div class="post-metadata">

**Author:** ![adamchainz](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/adamchainz/32/26_2.png) [@adamchainz](https://forum.djangoproject.com/u/adamchainz)\
**Post date:** [October 19, 2024, 11:38pm UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/10 "2024-10-19T23:38:14Z")

</div>

> [@carltongibson](#):
>
> @adamchainz Can I ask you to clarify exactly what you have in mind here?

The idea was to add a `{% set %}` tag that can add to the context without the nesting required by `{% with %}`. I didn’t mean that we’d add any other syntax from Jinja, like function calling. I believe that is what @apollo13 was suggesting.

I’ve seen a custom `{% set %}` tag on maybe one or two projects. I also think one of the older “utilities” packages used to provide it, but I can’t remember which or find it.

For example, this `{% with %}`:

```django
{% with total=engines.count %}
    <span data-total={{ total }}>{{ total }}</span> engines.
{% endwith %}

```

…could be replaced with:

```django
{% set total=engines.count %}
<span data-total={{ total }}>{{ total }}</span> engines.

```

Filters can still be used in variable declarations, so that allows some flexibility still.

---

<div class="post-metadata">

**Author:** ![christophehenry](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/christophehenry/32/14888_2.png) [@christophehenry](https://forum.djangoproject.com/u/christophehenry)\
**Post date:** [October 20, 2024, 12:23am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/11 "2024-10-20T00:23:15Z")

</div>

Ok, so leaving function call aside, I really don’t understand the opposition to extending `{% with %}` (and `{% set %}` for that matter) syntax to allow declaring common Python iterables (list, dicts, tuples and sets). This is not something that can simply be resolved by creating a new tag or filter. Let’s say I want a dict of tuples in my template:

1. I need to write `{% withdict %}`
2. I need to write `{% withtuple %}`
3. I need to write:

```auto
{% withtuple val1 val2 val3 as tuple1 %}
    {% withtuple val4 val5 val6 as tuple2 %}
        {% withtuple val7 val8 val9 as tuple3 %}
            {% withdict key1=tuple1 key2=tuple3 key3=tuple3 as my_dict %}
                … 
            {% endwithdict %}
        {% endwithtuple %}
    {% endwithtuple %}
{% endwithtuple %}

```

Is it really a better design than:

```auto
{% with my_dict={key1: (val1, val2, val3), … } %} 
{% endwith %}

```

?

---

<div class="post-metadata">

**Author:** ![carltongibson](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/carltongibson/32/267_2.png) [@carltongibson](https://forum.djangoproject.com/u/carltongibson)\
**Post date:** [October 20, 2024, 5:21am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/12 "2024-10-20T05:21:29Z")

</div>

@adamchainz the Slippers `var` tag is like this:

> **[Template tags and filters | slippers](https://mitchel.me/slippers/docs/template-tags-filters/#var)**
>
> Slippers includes a number of extra template tags and filters to help template authors build reusable components.

---

<div class="post-metadata">

**Author:** ![christophehenry](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/christophehenry/32/14888_2.png) [@christophehenry](https://forum.djangoproject.com/u/christophehenry)\
**Post date:** [October 20, 2024, 6:18am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/13 "2024-10-20T06:18:24Z")

</div>

That doesn’t solve the problem of defining common Python iterables, though. But I understand that this is added comlexity to the DTL and you need a good reason for that. So here is a practical use-case, very common that have met several times when working on Django projects.

Let’s say I have `{% my_custom_tag %}` that spits out whatever HTML. Now, as I use [Stimulus](https://stimulus.hotwired.dev), I want to be able to pass `data-*` attributes to that custom tag. Then I can’t use `@register.simple_tag` and pass `{% my_custom_tag data-controller="my-controller" %}` because this raises `TemplateSyntaxError: Could not parse the remainder: '-controller="my-controller"' from 'data-controller="my-controller"'`. If I want to be able to pass dashed HTML attributes as tag kwarg, I will have to go as far as writing a custom node that parses `"my-controller" as "data-controller"` [like I did on `dj-importmap`](https://github.com/christophehenry/dj-importmap/blob/main/importmap/templatetags/importmap.py#L72-L90).

Now, you could answer that I can define this in `get_context`. And, sure I can. But that breaks both separation of concerns and locality. It’s not data, it’s not logic, it’s HTML. It doesn’t belong in the view, it belongs in the template, like all the other HTML attributes that define the behavior of my controller.

I think that now the Django community has adopted JS frameworks heavily relying on HTML atttributes, like Stimulus or htmx as a standard, it could be a goo idea to support defining standard Python iterables in template variables.

Again: I understand the will to not add uneccessary comlexity to the language, which is why I propose to limit these to only `{% with %}` and `{% set %}`.

---

<div class="post-metadata">

**Author:** ![carltongibson](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/carltongibson/32/267_2.png) [@carltongibson](https://forum.djangoproject.com/u/carltongibson)\
**Post date:** [October 20, 2024, 9:52am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/14 "2024-10-20T09:52:07Z")

</div>

> [@boxed](#):
>
> … as you can’t have template tags per view.

I have a solution I use for this. I will package it up.

---

<div class="post-metadata">

**Author:** ![boxed](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/boxed/32/11975_2.png) [@boxed](https://forum.djangoproject.com/u/boxed)\
**Post date:** [October 20, 2024, 10:26am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/15 "2024-10-20T10:26:51Z")

</div>

Oooh. Interesting! I look forward to it.

---

<div class="post-metadata">

**Author:** ![nessita](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nessita/32/12194_2.png) [@nessita](https://forum.djangoproject.com/u/nessita)\
**Post date:** [October 21, 2024, 4:16pm UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/16 "2024-10-21T16:16:05Z")

</div>

> [@christophehenry](#):
>
> In particular, I’d love to create inline sequences like this first example:
> 
> ```auto
> {% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
> 
> ```
> 
> Also, shoud it enable calling arbitrary functions and not just filters with zero or 1 argument?
> 
> ```auto
> {% set ns = namespace(found=false) %}
> 
> ```
> 
> I would really love that too because I often found myself limited by DTL’s filter engine. And limiting this feature to only the `{% set %}` tag could be a way to experiment on evolving DTL’s syntax in a limited scope.

I’m -1 on this. While I see the appeal and temptation to have this new syntax available, it brings many complications that I’ll illustrate with an analogy:

Suppose the DTL is a recipe book. You have a limited set of recipes—most are great, some you may never try, and others you use often. You might tweak a few ingredients or cooking times, making notes in the same book (hopefully not) or rewriting your variations in a personal notebook. That’s fine. But you wouldn’t expect to find wheat seeds inside the book to grow your own flour. Those seeds can rot, grow uncontrollably, and contaminate your gluten-free kitchen with gluten.

My point is that Python inside DTL is out of place, an outlier. Python, like seeds, is powerful and we love using it to build great things, but there’s a time and place for it, and that isn’t within the recipe book.

If the analogy feels like a stretch (fair enough), my other concern is that allowing Python execution inside the DTL opens a can of worms, particularly regarding security, performance, and compatibility. These issues warrant a deeper examination and could have tangible consequences for maintaining the framework. I would say a change like this requires a DEP at the very least.

---

<div class="post-metadata">

**Author:** ![christophehenry](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/christophehenry/32/14888_2.png) [@christophehenry](https://forum.djangoproject.com/u/christophehenry)\
**Post date:** [October 21, 2024, 7:24pm UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/17 "2024-10-21T19:24:07Z")

</div>

Uh. I narrowed the scope of this discussion to just creating common iterables.

---

<div class="post-metadata">

**Author:** ![nessita](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nessita/32/12194_2.png) [@nessita](https://forum.djangoproject.com/u/nessita)\
**Post date:** [October 21, 2024, 7:38pm UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/18 "2024-10-21T19:38:35Z")

</div>

Yes, and I answered based on that. Creating iterables still requires Python evaluation in the template, and the whole “can of worms” argument applies (IMHO).

---

<div class="post-metadata">

**Author:** ![christophehenry](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/christophehenry/32/14888_2.png) [@christophehenry](https://forum.djangoproject.com/u/christophehenry)\
**Post date:** [October 22, 2024, 2:37am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/19 "2024-10-22T02:37:06Z")

</div>

> [@nessita](#):
>
> Creating iterables still requires Python evaluation in the template

Uh. No? Jinja doesn’t do it. Plus, has anyone here read [the use-case I exposed](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/13)?

---

<div class="post-metadata">

**Author:** ![carltongibson](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/carltongibson/32/267_2.png) [@carltongibson](https://forum.djangoproject.com/u/carltongibson)\
**Post date:** [October 22, 2024, 5:10am UTC](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787/20 "2024-10-22T05:10:18Z")

</div>

For that kind of case one creates a tag taking whatever parameters it needs and setting the context with the list/dict. (Or a filter that returns the same if that works.)

(For the function call case one could always take inspiration from JavaScript and define an _apply_ tag/filter.)

[Next page](https://forum.djangoproject.com/t/support-a-new-set-tag-and-defining-dicts-list-sets-and-tuples-in-with-and-set/35787.md?page=2)
