Hi all,
For being able to do AST manupulations on templates we need to keep the grammar of templatetags somewhere.
During the sprints, Russel told me to attach these as a property on the functions that go into Library.tags. (I would attach an instance of a class named TemplateTagMeta.)
For those who wonder what the applications are. They are mainly for template preprocessing, HTML validation, and code completion in editors, when writing Django templates.
For simple_tag, assignment_tag and inclusion tag. The grammar rules are easy.
For any other custom tag it's right now impossible to extract the grammar.
The reason is mainly that it is too complicated to define custom template tags which consist of an open/close tag.
It should certainly not be necessary to touch the (parser, token) tuple.
I propose that we introduce a new, more user-friendly way of defining these tags. I created register.block_tag, but I'm not sure about the API. This works, and it's is all we need for the built-in "if" template tag.
@register.block_tag('if elif* else? endif')
def do_if(parser, blocks):
conditions_nodelists = []
for name, bits, nodelist in blocks:
if name in ('if', 'elif'):
condition = TemplateIfParser(parser, bits).parse()
else:
condition = None
conditions_nodelists.append( (condition, nodelist) )
return IfNode(conditions_nodelists)
The advantage is that it's both much more easy to write custom template tags which have one or more "bodies", and that this declaration allows us to extract the grammar rules of templates. (Which can be used for preprocessing, or HTML validation.)
Note that we don't deprecate the old way of writing template tags. It's a public API. But we should discourage custom token/parser manupulation in custom template tags.
- What do you think about the name "block_tag"? I'm not sure. tag_with_grammar is too long, and the tag function itself cannot be changed anymore.
- What do you think about the syntax of the grammar. The space-separated notation is more often used in the Python core.
- Is the "parser" parameter really necessary. At least we need it in TemplateIfParser. But Why?
- register.block_tag works as well if the templatetags don't have a body. In that case, there's only one iteration through blocks, where nodelist is an empty list. Would this imply we need another name for "block_tag" or not? Otherwise we need something else for -- for instance -- the csrf_token template tag.
I'd also like to add a new management command to Django which prints the AST for templates. But in a human readable way. I think this would help a lot for developers to understand how the template tags of third party libraries work. And further, it would make it easier for people to write autocompletion plug-ins for a lot of editors.
What do you think would be good as a format, maybe the following?
<builtin>
if elif* else? endif
for empty? endfor
...
<admin>
...
Further, the following line does not say anything about the template tag parameters.
@register.block_tag('if elif* else? endif')
Should we add some syntax to tell which template tags have or don't have any parameters, or leave that to the implementation of block_tag?
Cheers,
Jonathan