Proposal: variable argument lists for templatetags, in templates.

204 views
Skip to first unread message

Przemek Czerkas

unread,
Jun 9, 2014, 3:38:40 AM6/9/14
to django-d...@googlegroups.com
Hi,

In this ticket https://code.djangoproject.com/ticket/13956 (Indefinite args for simpletags and inclusion tags) a support for *args and **kwargs for simple_tag, inclusion_tag and assignment_tag was added.

I think that one piece is still missing. How about allowing to pass *args/**kwargs to templatetag arguments:
{% some_tag [positional_args] [named_args] *args **kwargs %}
where args is a list, kwargs is a dict?

With this new syntax, the resolution of variable arguments would had to be moved to the render() phase, as well as some of the argument checking (e.g. {% with kwargs %} case for empty kwargs).

What do you think?

Regards,
Przemek Czerkas

Russell Keith-Magee

unread,
Jun 9, 2014, 6:14:21 PM6/9/14
to Django Developers
Hi Przemek,

I'm not entirely certain I understand what you're proposing here. simple_tag, inclusion_tag and assignment_tag are all utility classes that you use to produce template tags; however, all the "native" template tags have their own implementations - which includes, for the most part, their own parsing infrastructure. 

Note that I'm not necessarily defending this arrangement -- In the past, this has been the cause of inconsistencies in argument handling between tags. However, it is the status quo, and it needs to be taken into account - if only because The side effect of this arrangement is that any custom template tags out there are relying on the fact that variable resolution *doesn't* happen in the render phase - at least, not in any automated or semi-automated way.

So -  at a high level API level, what you are suggesting sounds interesting - *args and **kwargs are a powerful mechanism in python, and I can see how they might be useful in the context of template tags as a general feature - but I'm not sure I see how this would manifest in practice. The only two approaches I can see are:
 
1) a backwards incompatible change at the root level of template tag design, or

2) a manual change to each of Django's internal template tags - which would represent a lot of code churn to satisfy a use case that isn't entirely clear.

Are you able to clarify how you would see this change happening in practice?

Yours,
Russ Magee %-)

Przemek Czerkas

unread,
Jun 14, 2014, 11:37:46 AM6/14/14
to django-d...@googlegroups.com
On Tuesday, June 10, 2014 12:14:21 AM UTC+2, Russell Keith-Magee wrote:

Hi Przemek,

I'm not entirely certain I understand what you're proposing here. simple_tag, inclusion_tag and assignment_tag are all utility classes that you use to produce template tags; however, all the "native" template tags have their own implementations - which includes, for the most part, their own parsing infrastructure. 

Note that I'm not necessarily defending this arrangement -- In the past, this has been the cause of inconsistencies in argument handling between tags. However, it is the status quo, and it needs to be taken into account - if only because The side effect of this arrangement is that any custom template tags out there are relying on the fact that variable resolution *doesn't* happen in the render phase - at least, not in any automated or semi-automated way.


In my opinion those custom tags in the wild have to deal with this situation already (if I understand you right). For example InclusionNode with non-constant parameter (non-constant template name) will do the parsing of included template (and nodes/nodelist instantialisation) in de-facto render (global render) phase. If this is not what you meant, could you please explain further?
 
So -  at a high level API level, what you are suggesting sounds interesting - *args and **kwargs are a powerful mechanism in python, and I can see how they might be useful in the context of template tags as a general feature - but I'm not sure I see how this would manifest in practice. The only two approaches I can see are:
 
1) a backwards incompatible change at the root level of template tag design, or

2) a manual change to each of Django's internal template tags - which would represent a lot of code churn to satisfy a use case that isn't entirely clear.

Are you able to clarify how you would see this change happening in practice?

Well, it looks like the initialization of any templatetag by Django takes place in a single point (Django 1.5 here):

                self.enter_command(command, token)
                try:
                    compile_func = self.tags[command]
                except KeyError:
                    self.invalid_block_tag(token, command, parse_until)
                try:
                    compiled_result = compile_func(self, token)
                except TemplateSyntaxError as e:
                    if not self.compile_function_error(token, e):
                        raise
                self.extend_nodelist(nodelist, compiled_result, token)
                self.exit_command()
 
Maybe it would be sufficient to:
- modify class FilterExpression() to allow for a new syntax, i.e. parameters which starts with "*" and "**",
- preparse token.contents to see, if variable parameters (varargs) were passed,
- if no varargs were passed, take normal code path,
- else validate, that varargs are in right order/position with the respect to the rest of arguments,
- wrap "compiled_result = compile_func(self, token)" call with some object that defers underlying tag initialization to the render phase,
- in render phase call underlying tag initalization with varargs replaced with values resolved from the current context.

Without actual implementation it is hard to say more. As usual, the devil is in the detail (probably)

Regards,
Przemek Czerkas

Przemek Czerkas

unread,
Nov 9, 2014, 4:40:11 AM11/9/14
to django-d...@googlegroups.com


On Tuesday, June 10, 2014 12:14:21 AM UTC+2, Russell Keith-Magee wrote:

Hi Przemek,

I'm not entirely certain I understand what you're proposing here. simple_tag, inclusion_tag and assignment_tag are all utility classes that you use to produce template tags; however, all the "native" template tags have their own implementations - which includes, for the most part, their own parsing infrastructure. 

Note that I'm not necessarily defending this arrangement -- In the past, this has been the cause of inconsistencies in argument handling between tags. However, it is the status quo, and it needs to be taken into account - if only because The side effect of this arrangement is that any custom template tags out there are relying on the fact that variable resolution *doesn't* happen in the render phase - at least, not in any automated or semi-automated way.

So -  at a high level API level, what you are suggesting sounds interesting - *args and **kwargs are a powerful mechanism in python, and I can see how they might be useful in the context of template tags as a general feature - but I'm not sure I see how this would manifest in practice. The only two approaches I can see are:
 
1) a backwards incompatible change at the root level of template tag design, or

2) a manual change to each of Django's internal template tags - which would represent a lot of code churn to satisfy a use case that isn't entirely clear.

Are you able to clarify how you would see this change happening in practice?

Yours,
Russ Magee %-)

Hi Russ,

I've added patch with proposed functionality, tests included: https://code.djangoproject.com/ticket/13956#comment:34
Now I'm working on documentation.

Regards
Reply all
Reply to author
Forward
0 new messages