Proposal: {% include_partial %} template tag

43 views
Skip to first unread message

Marco Louro

unread,
Jun 7, 2010, 6:03:09 AM6/7/10
to Django developers
Hi all,

I'd like to propose adding a tag that includes a template with clean
context, but can accept parameters that will be added to that
context.

The use-cases are plenty, but I've been using it mostly with forms, as
it helps to keep the template code DRY and very customizable. We could
use the {% with %} and {% include %} tags to do the same of course,
but I think something like {% include_partial "forms/textfield.html"
field=person_form.first_name label="First Name:" %} is much cleaner.

This is similar to a rails tag called "render_partial" and there's a
draft at http://gist.github.com/427116 based on
http://freeasinbeard.org/post/107743420/render-partial-in-django


Thanks

bur...@gmail.com

unread,
Jun 7, 2010, 6:58:12 AM6/7/10
to django-d...@googlegroups.com
Hi Marco,

Please also get a look at http://github.com/buriy/django-containers
Which implements exactly the same, but allows larger chunks:
{% part left%}{% trans "arbitrary contents" %}{% endpart %}.

--
Best regards, Yuri V. Baburov, ICQ# 99934676, Skype: yuri.baburov,
MSN: bu...@live.com

Jacob Kaplan-Moss

unread,
Jun 7, 2010, 12:13:44 PM6/7/10
to django-d...@googlegroups.com
On Mon, Jun 7, 2010 at 5:03 AM, Marco Louro <mlo...@gmail.com> wrote:

> I'd like to propose adding a tag that includes a template with clean
> context, but can accept parameters that will be added to that
> context.

Is there a reason to do this as a separate tag? Why not just::

{% include "some/template.html" with foo=bar baz=spam %}

?

Jacob

Łukasz Rekucki

unread,
Jun 7, 2010, 12:35:11 PM6/7/10
to django-d...@googlegroups.com
Personally, I would expect this to extend the current context with
"foo" and "bar", render the include and restore foo, bar to old values
(if any). Using a clean context instead is a bit non-obvious to me.

--
Łukasz Rekucki

Javier Guerra Giraldez

unread,
Jun 7, 2010, 12:41:18 PM6/7/10
to django-d...@googlegroups.com
2010/6/7 Łukasz Rekucki <lrek...@gmail.com>:

>>    {% include "some/template.html" with foo=bar baz=spam %}
> Personally, I would expect this to extend the current context with
> "foo" and "bar", render the include and restore foo, bar to old values
> (if any). Using a clean context instead is a bit non-obvious to me.

what about:

{% include "some/template.html" with foo=bar baz=spam %}

=> adds varaibles 'foo' and 'baz' to current context

{% include "some/template.html" withonly foo=bar baz=spam %}
=> replaces current context with one having just 'foo' and 'baz'

--
Javier

Marco Louro

unread,
Jun 7, 2010, 1:52:55 PM6/7/10
to Django developers
I'd prefer extending the {% include %} tag actually, but didn't of
that in the first place.

The clean context implementation was to make sure we don't pass
variables we don't want to. One of the use-cases is including form
field "templates", so I have code like:

<pre>
<div class="row textfield {% if field.errors %}error{% endif %} {% if
field.field.required %}required{% endif %}">
<div class="label">
{% if label %}
<label>{{ label }}</label>
{% else %}
{{ field.label_tag }}
{% endif %}
</pre>

if there was a "label" variable in the context but not in the
parameters, the code above would output the wrong values. There is one
problem with not inheriting the context: {% csrf_token %} will fail.

Gabriel Hurley

unread,
Jun 7, 2010, 2:59:54 PM6/7/10
to Django developers
Extending the include tag seems like a fantastic idea! I end up
writing the {% with %}{% include %} combo all the time for my reusable
template snippets.

However, I feel like selectively clearing the context inside a
template tag is asking for trouble and/or confusion. It also sounds
like it goes against Django's "templates require no knowledge of
programming" principle. While I can see how you might run into context
name collisions in a *very* large or complicated project, the right
solution there seems like it ought to be to clean up your context and/
or templates outside of the template itself... Even in projects with
dozens of installed apps (both my own and third-party ones mixed
together) I've never had that problem where two minutes of tweaking
couldn't fix it for good.

I'm certainly not saying you don't have a use case for it, or that it
wouldn't be extremely helpful to you. Just that having a tag that
clears the context sounds fishy to me...

All the best,

- Gabriel

Jeliuc Alexandr

unread,
Jun 8, 2010, 3:10:22 AM6/8/10
to Django developers
Hi, Marco

Do You use symfony?

Marco Louro

unread,
Jun 8, 2010, 5:27:22 AM6/8/10
to Django developers
Gabriel,

I only made that decision because I didn't see the need to have whole
context, and the only time I have needed it was because of the {%
csrf_token %}. This is just my use-case, but I understand that other
people might want to use it differently. I don't think it makes much
of a difference, a clean context may avoid some collisions from time
to time, but it may have bigger drawbacks for other people.


Hi Jeliuc,

No, I don't.
> > On Jun 7, 5:35 pm, £ukasz Rekucki <lreku...@gmail.com> wrote:
>
> > > On 7 June 2010 18:13, Jacob Kaplan-Moss <ja...@jacobian.org> wrote:> On Mon, Jun 7, 2010 at 5:03 AM, Marco Louro <mlo...@gmail.com> wrote:
>
> > > >> I'd like to propose adding a tag that includes a template with clean
> > > >> context, but can accept parameters that will be added to that
> > > >> context.
>
> > > > Is there a reason to do this as a separate tag? Why not just::
>
> > > >    {% include "some/template.html" with foo=bar baz=spam %}
>
> > > Personally, I would expect this to extend the current context with
> > > "foo" and "bar", render the include and restore foo, bar to old values
> > > (if any). Using a clean context instead is a bit non-obvious to me.
>
> > > --
> > > £ukasz Rekucki

Gonzalo Saavedra

unread,
Jun 8, 2010, 12:30:40 PM6/8/10
to django-d...@googlegroups.com
I'm +1 on the optional "with" parameter for {% include %}. -1 on
adding a new tag for this.

I also use {% with %}{% include %} a lot in templates but we should
follow with/blocktrans syntax for consistency:

{% include "part.html" with obj.title|capfirst as title and "large"
as main_class %}


A related proposal for the "with" tag: It'd be nice to support more
than one variable definition (as blocktrans does):

{% with "a" as var1 and "b" as var2 %}...{% endwith %}

The current solution is nesting "with" tags, which is not very pretty.


gonz.


2010/6/8 Marco Louro <mlo...@gmail.com>:

[...]

Łukasz Rekucki

unread,
Jun 8, 2010, 1:22:18 PM6/8/10
to django-d...@googlegroups.com
On 8 June 2010 18:30, Gonzalo Saavedra <gonzalo...@gmail.com> wrote:
> I'm +1 on the optional "with" parameter for {% include %}. -1 on
> adding a new tag for this.
>
> I also use {% with %}{% include %} a lot in templates but we should
> follow with/blocktrans syntax for consistency:
>
>  {% include "part.html" with obj.title|capfirst as title and "large"
> as main_class %}
Was about to propose the same thing :)

> A related proposal for the "with" tag: It'd be nice to support more
> than one variable definition (as blocktrans does):
>
>  {% with "a" as var1 and "b" as var2 %}...{% endwith %}
>
> The current solution is nesting "with" tags, which is not very pretty.
>

As the next step to make something happen is to create a ticket, I
found this on trac: http://code.djangoproject.com/ticket/7817

I'm willing to improve the existing patch, so I assigned it to myself.
The ticket is marked as DDN, so I guess this thread is a request to
accept it.

--
Łukasz Rekucki

bur...@gmail.com

unread,
Jun 8, 2010, 1:33:04 PM6/8/10
to django-d...@googlegroups.com
I'd suggest to change both include and with/blocktrans syntax into
more programmer-friendly style:

{% include "part.html" title=obj.title|capfirst main_class="large" %}

This is both more dense, and from quick grasp you can see where are
the delimiters ("as" is not so good for this).

Also I think we need an argument to tell that outer context is passed inside.

> --
> You received this message because you are subscribed to the Google Groups "Django developers" group.
> To post to this group, send email to django-d...@googlegroups.com.
> To unsubscribe from this group, send email to django-develop...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.

Gregor Müllegger

unread,
Jun 8, 2010, 1:47:08 PM6/8/10
to django-d...@googlegroups.com
Also +1 from me for extending the include tag instead of having a new one.

Bye default it should keep its behaviour and use the current context
for the included template. Marco's use of a new, clean context
(demonstrated with the snippet below) is also possible to support.

{% if label %}
<label>{{ label }}</label>
{% else %}

You can just pass in an empty string, like one of the following three examples:

{% include "part.html" with label= title=obj.title %}
{% include "part.html" with label="" title=obj.title %}
{% include "part.html" with "" as label and obj.title as title %}

(I don't want to propose the implementation of all three syntaxes. I
just want to demonstrate that all possible syntaxes can handle Marco's
usecase.)

--
Servus,
Gregor Müllegger

2010/6/8 bur...@gmail.com <bur...@gmail.com>:

Jonathan S

unread,
Jul 9, 2010, 9:15:51 AM7/9/10
to Django developers
Something related, that we could really use is passing not just
variables to the include, but also blocks. I tried to implement a
template tag for this, but it doesn't work together with how Django
replaces blocks in the extended template at compile time instead of
during the renderering.

I would like to do:

## in the main template:
...
{% include "decorator.html" %}
{% block "content" %}
...
{% endblock %}
{% endinclude %}
...

## In decorator.html


<div class="...">
{% block content %}{% endblock %}
</div>

##
So, the main templates includes decorator.html, but replaces the inner
block "content", by the block it passes to the include.
The decorator pattern, wraps the input in some nodes.

There are use cases where this is required to keep the templates DRY.
I think only a few templating languages are able to do this.
The .NET framework supports the design pattern pretty well, as far as
I remember.

The alternative in this particular example is to use two include tags
"before.html" and "after.html", but is ugly because the opening and
closing html tag are separated over different files.

-- Jonathan


On 8 juin, 19:47, Gregor Müllegger <gre...@muellegger.de> wrote:
> Also +1 from me for extending the include tag instead of having a new one.
>
> Bye default it should keep its behaviour and use the current context
> for the included template. Marco's use of a new, clean context
> (demonstrated with the snippet below) is also possible to support.
>
>        {% if label %}
>        <label>{{ label }}</label>
>        {% else %}
>
>  You can just pass in an empty string, like one of the following three examples:
>
>     {% include "part.html" with label= title=obj.title %}
>     {% include "part.html" with label="" title=obj.title %}
>     {% include "part.html" with "" as label and obj.title as title %}
>
> (I don't want to propose the implementation of all three syntaxes. I
> just want to demonstrate that all possible syntaxes can handle Marco's
> usecase.)
>
> --
> Servus,
> Gregor Müllegger
>
> 2010/6/8 burc...@gmail.com <burc...@gmail.com>:
> >> For more options, visit this group athttp://groups.google.com/group/django-developers?hl=en.
Reply all
Reply to author
Forward
0 new messages