Proposal: allow simple_tag to parse @/- attributes

As it currently stands, passing attributes that contain @ and/or - to template tags implemented using @simple_tag raises an error.

Example:

@register.simple_tag
def greetings(*args, **kwargs):
    return 'greetings'

template:

{% greetings @click='' %}

error:

TemplateSyntaxError at /

Could not parse the remainder: '@click=''' from '@click='''

This errors regardless of the greetings implementation, since the decorator makes it fail upstream.

Alpine.js, htmx, and similar libraries are fairly popular these days. I believe it only makes sense to simplify the use of their attributes in cases that wouldn’t require a custom template.Node otherwise.

I think this is more likely an issue of nested quotes than of the ability to pass the tag.

All these following work:

{% greetings '@click=" " ' %}

{% greetings '@click=\' \' ' %}

{% greetings "@click=\" \" " %}

{% greetings "@click='  ' " %}

That seems like a different thing than what OP is asking for. He’s saying it would be useful to loosen the restriction of the syntax for keyword arguments in simple tags from <python_style_identifier>= to <printable_word>=.

I’m not sure I agree, but I can see why if you want to map JS libs that do this type of thing directly, and you have to mix @foo= with foo=.

Yes, I can see where that could be what’s being looked for, but given how those identifiers are (can be) used as a keyword arg, the limitation here is more one of python than Django - unless you want to completely change the semantics of that tag - in which case this becomes a much wider issue.

In Python you can pass any string as keyword argument though:

In [1]: def foo(**kwargs):
   ...:     print(kwargs)
   ...: 

In [2]: foo(**{"@hello!!": 1})
{'@hello!!': 1}

Yes, but you can’t accept it as a named parameter:
def foo(@hello!!): isn’t going to work, which means the function must access these by using kwargs, creating the situation where some of the template variables could be received directly, but some must not.

Sure. The limitations of Python still apply, but that is a separate question from what the template language should/could support I think.

I am +1 to this proposal, perhaps with an opt-in argument like @simple_tag(allow_all_attrs=True).

My heroicons package provides template tags made with simple_tag that allow setting hyphenated attributes, but it requires accepting attributes with _ and translating them to -

The HTML specification for attribute names allows pretty much any character:

Attribute names must consist of one or more characters other than controls, U+0020 SPACE, U+0022 ("), U+0027 ('), U+003E (>), U+002F (/), U+003D (=), and noncharacters.

I don’t think we can provide that level of flexibility without breaking parsing, but allowing some common punctuation (@, :, -) should be feasible…

1 Like

Thanks all for the feedback.

The question now is how to handle the function arguments.
I think the simpler, and probably most sensible, solution is to not support named arguments for attributes that contain python-disallowed argument characters. Basically only be able to access their values by kwargs["@hello"].
We could otherwise translate them somehow, as Adam describes. It might be too “magical” of a solution though, particularly for parameters with : and @.

1 Like