Opened 5 years ago

Closed 4 years ago

#14262 closed New feature (fixed)

Helper for "get_something as varname" template tag pattern

Reported by: carljm Owned by: nobody
Component: Template system Version: master
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX:

Description

It's a common pattern to write a template tag that fetches some data and sticks it in a context variable. Currently writing these tags requires writing a full-blown parsing function and Node class, which is mostly boilerplate except for the render() method. It would be good to have a template tag helper for writing tags that follow this pattern. (Similar to simple_tag, except allowing for updating the context).

Attachments (3)

14262.assignment_tag.diff (13.6 KB) - added by julien 4 years ago.
14262.assignment_tag.2.diff (13.3 KB) - added by julien 4 years ago.
Updated patch to current trunk
14262.assignment_tag.3.diff (12.3 KB) - added by julien 4 years ago.
Small doc fixes

Download all attachments as: .zip

Change History (14)

comment:1 Changed 5 years ago by carljm

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

Per design conversation with Jannis, Malcolm, and Russell at sprint, marking as Accepted and superseding #1105.

comment:2 follow-up: Changed 4 years ago by julien

I'm keen to write a patch for this, but first I'd like to be sure of the intent with this decorator. The name "assignment_tag" has been suggested in (1). Now which API do you anticipate? Is it one of the following:

{% my_tag arg1 arg2 %}

@register.assignment_tag
def my_tag(arg1, arg2, ...):
    ...
    return {
            'key1': value1,
            'key2': value2,
        } # These keys/values will be added to the context

or:

{% my_tag arg1 arg2 as blah %}

@register.assignment_tag
def my_tag(arg1, arg2, ...):
    ...
    return value # This will be set to the variable 'blah' in the context

or else?

Also, it might be useful to have access to the context itself (at least in read-only mode) from within that tag. If you agree, then what would the API be?

(1) http://groups.google.com/group/django-developers/browse_thread/thread/fbf7d9fd8f256b17/

comment:3 in reply to: ↑ 2 Changed 4 years ago by carljm

Replying to julien:

Now which API do you anticipate?

Definitely the latter ({% mytag arg1 arg2 as blah %}), with the varname explicitly specified in the template.

The other encourages a pattern where the keys to update in the context are fixed in the tag, which makes the tag less flexible and the template less readable. Of course it's possible to have those keys passed in, but it makes it more work to do things right and easier to do them wrong.

Also, it might be useful to have access to the context itself (at least in read-only mode) from within that tag. If you agree, then what would the API be?

Now that both inclusion_tag and simple_tag have takes_context, I see no reason not to carry that consistency to this shortcut as well, and have a takes_context arg that works the same way. I know this leaves room for people to do wierd and confusing things where they update the context themselves in the tag code, and then also return something for the automatic assignment_tag update; but on the whole I think the value of consistency with the other shortcuts outweighs that minor concern.

I'd also note that with the #14908 fix, it's now possible to write a simple_tag like this:

@register.simple_tag(takes_context=True)
def get_foo(context, _as, varname):
    # ... fetch some data ...
    context[varname] = ...
    return ''

Which achieves the same thing as assignment_tag, although using it in a template requires unsightly quoting of both "as" and the target varname: {% get_foo "as" "bar" %}.

I'm still in favor of adding assignment_tag, to make the syntax nicer in the template and make the technique more explicit.

comment:4 Changed 4 years ago by julien

I totally agree there should be an explicit and designer-friendly way of assigning values so I too am in favour of introducing this new decorator. My only concern now is that some times you may want to assign multiple values after executing some expensive calculations (e.g. heavy database queries), so it would be great if something like the following could be achieved:

{% get_values arg1 arg2 as var1 var2 %}

@register.assignment_tag
def get_values(arg1, arg2):
    ... expensive calculations ...
    return (foo, bar) # foo would be assigned to 'var1' and foo to 'var2'.

If multiple variables were specified after the 'as' then the tag would be expected to return a list or tuple. If only one variable were specified, then whatever is returned by the tag would be assigned to that variable (a single value or a list or whatever).

If this idea is rejected, then at least one will still be able to do the following:

{% get_values arg1 arg2 as var %} {# Tag returns a list #}

{{ var.0 }} and {{ var.1 }}

... less explicit but no big deal.

What do you think?

comment:5 Changed 4 years ago by carljm

The multiple-assignment version is a poor tradeoff of adding complexity to support an edge case, when just assigning a list (or a dict for better template readability) works just fine. And if you have complex needs, you write a Node. The simple shortcuts are for simple cases.

comment:6 Changed 4 years ago by julien

Also check out #2016 which was in fact the first ticket to ask for this new functionality and has patches.

comment:7 Changed 4 years ago by julien

  • Severity set to Normal
  • Type set to Uncategorized

See #6378 for a related feature request (capturing template output).

comment:8 Changed 4 years ago by SmileyChris

  • Type changed from Uncategorized to New feature

Changed 4 years ago by julien

comment:9 Changed 4 years ago by julien

  • Easy pickings unset
  • Has patch set

I've attached a patch which implements this new feature and includes tests and doc. Any feedback welcome ;)

Changed 4 years ago by julien

Updated patch to current trunk

Changed 4 years ago by julien

Small doc fixes

comment:10 Changed 4 years ago by jezdez

  • Triage Stage changed from Accepted to Ready for checkin

comment:11 Changed 4 years ago by jezdez

  • Resolution set to fixed
  • Status changed from new to closed

In [16149]:

Fixed #14262 -- Added new assignment_tag as a simple way to assign the result of a template tag to a context variable. Thanks, Julien Phalip.

Note: See TracTickets for help on using tickets.
Back to Top