Opened 16 years ago
Last modified 11 years ago
#5865 new New feature
cycle template tag should accept a single argument
Reported by: | Gary Wilson | Owned by: | munhitsu |
---|---|---|---|
Component: | Template system | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | mateusz@… | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | yes |
Needs tests: | yes | Patch needs improvement: | yes |
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 (18)
comment:1 Changed 16 years ago by
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 Changed 16 years ago by
Owner: | changed from nobody to munhitsu |
---|
comment:3 follow-up: 5 Changed 16 years ago by
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 Changed 16 years ago by
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 Changed 16 years ago by
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 Changed 16 years ago by
Cc: | mateusz@… 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 Changed 16 years ago by
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 Changed 16 years ago by
Resolution: | fixed |
---|---|
Status: | closed → reopened |
comment:9 Changed 16 years ago by
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 Changed 16 years ago by
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,'),
Changed 16 years ago by
Attachment: | cycle-doc.diff added |
---|
comment:11 Changed 16 years ago by
Cc: | mateusz@… added; mateusz@… removed |
---|---|
Needs documentation: | unset |
comment:12 Changed 13 years ago by
Severity: | → Normal |
---|---|
Type: | → New feature |
comment:13 Changed 13 years ago by
Easy pickings: | unset |
---|---|
Triage Stage: | Accepted → Design decision needed |
A design decision hasn't been reached yet.
comment:14 Changed 12 years ago by
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 Changed 12 years ago by
Needs documentation: | set |
---|---|
Needs tests: | set |
Patch needs improvement: | set |
comment:16 Changed 11 years ago by
Status: | reopened → new |
---|
This sounds like a sensible improvement