Opened 17 years ago
Last modified 10 months ago
#5865 new New feature
cycle template tag should accept a single argument
Reported by: | Gary Wilson | Owned by: | |
---|---|---|---|
Component: | Template system | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | mateusz@… | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When passed a single argument, the cycle tag should treat it as an iterable to cycle through. For example, with the context:
{'colors': ['red', 'blue', 'green']}
you should be able to have a template like:
{% for row in mydata %} <tr class="{% cycle colors %}">...</tr> {% endfor %}
that would output:
<tr class="red">...</tr> <tr class="blue">...</tr> <tr class="green">...</tr> <tr class="red">...</tr> ...
Attachments (2)
Change History (28)
comment:1 by , 17 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 17 years ago
Owner: | changed from | to
---|
follow-up: 5 comment:3 by , 17 years ago
I'm a little concerned that this is ambiguous when you're reading it: you can't easily tell if it's referring to a previously named "cycle" tag or creating a new one using a variable as an iterator.
Is there a better way to write this that won't cause confusion when reading templates?
comment:4 by , 17 years ago
So far I've managed to perform the request but maintaining compatibility with older approach makes my code not so... clean.
What do you think about a new keyword i.e.: cycletable?
Maybe its a time to refer to named cycle tag by variable reference? To be honest referring by name is not to clear for me.
comment:5 by , 17 years ago
Replying to mtredinnick:
I'm a little concerned that this is ambiguous when you're reading it: you can't easily tell if it's referring to a previously named "cycle" tag or creating a new one using a variable as an iterator.
Is it really that different from using the "as varname" syntax of other tags or the {% with %}
tag though? The way I see it, when you encounter any variable name in the templates, you have to check where it came from. Was it passed in the context? Was it defined as the target of "as varname" syntax of another variable? Was it defined with a with tag? Is it a loop variable? etc. This would be no different.
comment:6 by , 17 years ago
Cc: | added |
---|
Guys take a look at following unit test suite. Does it reflect your expectations?
{ 'cycle20': ("{% cycle colors %}", {'colors': 'red'}, template.TemplateSyntaxError), 'cycle21': ("{% cycle colors %}{% cycle colors %}", {'colors': ['red', 'blue', 'green']}, 'redblue'), 'cycle22': ("{% cycle colors %}{% cycle colors %}{% cycle colors %}", {'colors': ['red', 'blue', 'green']}, 'redbluegreen'), 'cycle23': ("{% cycle colors %}{% cycle colors %}{% cycle colors %}{% cycle colors %}", {'colors': ['red', 'blue', 'green']}, 'redbluegreenred'), 'cycle24': ("{% cycle colors as color %}{% cycle color %}", {'colors': ['red', 'blue', 'green']}, 'redblue'), 'cycle25': ("{% cycle colors as color %}{% cycle color %}{% cycle color %}", {'colors': ['red', 'blue', 'green']}, 'redbluegreen'), 'cycle26': ("{% cycle colors as color %}{% cycle color %}{% cycle color %}{% cycle color %}", {'colors': ['red', 'blue', 'green']}, 'redbluegreenred'), 'cycle27': ("{% for i in test %}{% cycle colors %}{{ i }},{% endfor %}", {'test': range(5),'colors': ['a', 'b']}, 'a0,b1,a2,b3,a4,'), }
comment:7 by , 17 years ago
Has patch: | set |
---|---|
Resolution: | → fixed |
Status: | new → closed |
Seems to be working. Old regression is passing. New has been added.
I've added a small enhancement - a cycle pushed to context. Thanks to it cycle internals can be used inside template.
context['cycle'] = { # cycle internals 'collection': self.collection, 'name':self.variable_name, 'value':value, }
One note. Last part of syntax parsing has to be done in render method. We need context to say if {% cycle colors %} refers to table or is a mistake.
comment:8 by , 17 years ago
Resolution: | fixed |
---|---|
Status: | closed → reopened |
comment:9 by , 17 years ago
Needs documentation: | set |
---|---|
Patch needs improvement: | set |
Your cycle20 test case should not raise a TemplateSyntaxError
, but rather should output "r" since a string is iterable. A TemplateSyntaxError
should only be raised if the syntax for the tag in not correct, i.e. {% cycle colors as %}
. If the object passed is not iterable, the template tag should fail silently and return an empty string. Also, your patch should allow any iterable instead of just lists. I also don't see a reason that we should be exposing the internal state of the tag. Could you explain your reasoning for wanting to do that?
comment:10 by , 17 years ago
Patch needs improvement: | unset |
---|
Replying to gwilson:
Thanks for the comments.
- Functionality for test cycle20 updated. Do you have an idea how to prepare context with non iterable variable? I have no clue how to make unit test for it.
'cycle20': ("{% cycle colors %}", {'colors': 'r'}, 'r')
- Regarding silent fail... Actual implementation will throw TemplateSyntaxError for test cycle01 as original one. But i.e if 'a' would be defined in context than it will fall back to Variable('a').resolve(context).
'cycle01': ('{% cycle a %}', {}, template.TemplateSyntaxError)
- I've just added NameError exception catch as a backup to make sure we will fail silently
- Cycle patch now iterates over everything that is iterable - see test cycle22. It's hashed as Python does not guarantee iteration sequence on hash.
'cycle22': ("{% cycle colors %}{% cycle colors %}", {'colors': {'r': 1, 'g': 2}}, 'rg')
- Regarding cycle internal state in tag. I must say that I was inspired by ForNode and cycle is a somehow close to it. Take a look at tests cycle28..29. That the only reasonable case that I see now to use cycle internals. It's your choice.
'cycle28': ("{% for i in test %}{% cycle colors %}{{ cycle.value }}{{ i }},{% endfor %}", {'test': range(5),'colors': ['r', 'g', 'b']}, 'rr0,gg1,bb2,rr3,gg4,'), 'cycle29': ("{% for i in test %}{% cycle colors %}{% cycle colors %}{{ i }},{% endfor %}", {'test': range(5),'colors': ['r', 'g', 'b']}, 'rg0,br1,gb2,rg3,br4,'),
by , 17 years ago
Attachment: | cycle-doc.diff added |
---|
comment:11 by , 17 years ago
Cc: | added; removed |
---|---|
Needs documentation: | unset |
comment:12 by , 14 years ago
Severity: | → Normal |
---|---|
Type: | → New feature |
comment:13 by , 14 years ago
Easy pickings: | unset |
---|---|
Triage Stage: | Accepted → Design decision needed |
A design decision hasn't been reached yet.
comment:14 by , 13 years ago
Triage Stage: | Design decision needed → Accepted |
---|---|
UI/UX: | unset |
Discussion with Carl: this new syntax would be ambiguous with the current syntax, however this is a good feature, and the current API is kind of silly. This is accepted, provisional on creating a new, more sane and consistent syntax, to be placed in the future module.
comment:15 by , 13 years ago
Needs documentation: | set |
---|---|
Needs tests: | set |
Patch needs improvement: | set |
comment:16 by , 12 years ago
Status: | reopened → new |
---|
comment:18 by , 11 months ago
Replying to Alexander Lazarević:
Is this still considered a desirable feature?
Yes, IMO nothing has changed.
comment:19 by , 11 months ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:21 by , 11 months ago
Needs documentation: | unset |
---|---|
Needs tests: | unset |
Patch needs improvement: | unset |
For the new PR I'm going to remove "Needs documentation", "Needs tests" and "Patch needs improvement". Please set these flags again if required (or I should have left them set in the first place).
follow-up: 23 comment:22 by , 10 months ago
I just put something together at https://sandbox.e11bits.com/ to showcase the feature more broadly. Maybe people can judge by that, if the feature is desirable and help with the code review? It's just a quick hack, so don't expect too much. The examples are more or less the ones found as testcases in the PR. (crossposted to discord)
comment:23 by , 10 months ago
Replying to Alexander Lazarević:
I just put something together at https://sandbox.e11bits.com/ to showcase the feature more broadly. Maybe people can judge by that, if the feature is desirable and help with the code review? It's just a quick hack, so don't expect too much. The examples are more or less the ones found as testcases in the PR. (crossposted to discord)
Thank you Alexander for your work on this. In order to unify the conversation in a single place, I will reply to the forum thread with my view, hopefully we can agree on an implementation design there and then come back to the ticket.
As a reference, this is the forum post.
comment:24 by , 10 months ago
After the discussion in https://forum.djangoproject.com/t/cycle-template-tag-should-accept-a-single-argument/27010/3 I'm withdrawing the PR.
My implementation would have introduced an ambiguity that would have had it made it harder for users to use the cycle
tag.
In the discussion @carlton mentioned that it could be worth "... to investigate [is] whether we could add * and list and dictionary expansion to the DTL. cycle could benefit from list expansion.".
So I'm trying to come up with something in that direction instead.
comment:26 by , 10 months ago
Owner: | removed |
---|---|
Status: | assigned → new |
This sounds like a sensible improvement