Code

Opened 7 years ago

Closed 6 years ago

Last modified 4 years ago

#5172 closed (wontfix)

Extend the {% for %} tag to work as a simple loop

Reported by: SmileyChris Owned by: nobody
Component: Template system Version:
Severity: Keywords: for-tag enhancement feature
Cc: me@…, danielcristian@… Triage Stage: Design decision needed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

It's come up several times in IRC that people wanted to be able to just do a simple loop (repeat this X times) in their template.

The attached patch extends the {% for %} tag so it can also work like this:

{% for 5 %}
repeat me
{% endfor %}

It also works with integer variables and the forloop variable is still available within the loop:

{% for my_integer %}
loop: {{ forloop.counter }}
{% endfor %}

Attachments (2)

simple-for.patch (6.0 KB) - added by SmileyChris 7 years ago.
numerical-foo-loop.diff (5.6 KB) - added by gnuvince 7 years ago.

Download all attachments as: .zip

Change History (16)

Changed 7 years ago by SmileyChris

comment:1 Changed 7 years ago by SmileyChris

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Design decision needed

Tests and docs included, just need a decision.

comment:2 Changed 7 years ago by adrian

Hmm, this one merits some discussion. I like the general idea but need to mull over the syntax.

comment:3 Changed 7 years ago by PhiR

  • Keywords feature added

Changed 7 years ago by gnuvince

comment:4 Changed 7 years ago by gnuvince

  • Needs documentation set

I added a patch of my own. It's more complex than SmileyChris' and needs documentation (and possibly more tests.) Let me know what you think of the general syntax. The patch is attached.

Example usage:

{% for i 1 to 5 %}
    {{ i }}
{% endfor %}

{% for i 1 to 5 by 2 exclusive %}
    {{ i }}
{% endfor %}

{% for i 5 to 1 by -2 %}
    {{ i }}
{% endfor %}

comment:5 Changed 7 years ago by anonymous

Ugh, I don't like at all, sorry gnuvince. The aim isn't to make Django templates into python...

comment:6 follow-up: Changed 7 years ago by durdinator

  • Cc me@… added

Why a significant syntax change instead of a one-liner filter?

@register.filter
def times(count):
    return range(int(count))
{% for item in 5|times %}
  repeat me
{% endfor %}

comment:7 in reply to: ↑ 6 Changed 7 years ago by SmileyChris

Replying to durdinator:

Why a significant syntax change instead of a one-liner filter?

Because it looks simpler (and it's a syntax extension, really) and because then you're stuck with a pointless item context var.

Neither of which are convincing arguments. And talking about this at sprint, it seemed like the core would just prefer to have a new filter named something separate anyway so I don't hold much hope for my patch really :)

comment:8 Changed 7 years ago by gnuvince

How about something like:

{% times 5 %}
    {{ times.iter0 }}
    {{ times.iter1 }}
    <br />
{% endtimes %}

# Output
0 1
1 2
2 3
3 4
4 5

comment:9 Changed 7 years ago by gnuvince

P.S.: times is just a tentative name. I think repeat would be better.

comment:10 Changed 7 years ago by SmileyChris

And that's why I like it attached to {% for %} - then you get all of the forloop context variable goodness for free.

comment:11 follow-up: Changed 6 years ago by jacob

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

I just can't come up with a use case that isn't something better done in a view or better done by just writing out the rows by hand. Besides, this is a pretty simple thing to add as a custom tag in your app.

comment:12 Changed 6 years ago by danielcristian

  • Cc danielcristian@… added
  • Resolution wontfix deleted
  • Status changed from closed to reopened

I had this model:

class Mana(models.Model):
    name = models.CharField(u'Mana', max_length=200, unique=True)
    image = models.ImageField(u'Symbol', upload_to='manas/')

class Cost(models.Model):
    card = models.ForeignKey(Card)
    quantity = models.IntegerField('Quantity', max_length=2)
    mana = models.ForeignKey(Mana, related_name=u'mana', verbose_name=u'Mana')

(Yes, it's related to Magic Cards...)

Some cards had a cost with a quantity value (1 Forest, 3 Islands, 5 Mountains), and I need to loop quantity times to show n-times the image cost.

It could be done with this kind of loop.

comment:13 Changed 6 years ago by ubernostrum

  • Resolution set to wontfix
  • Status changed from reopened to closed

Please do not reopen a ticket that's been marked "wontfix" by a core developer; if you strongly disagree, consider starting a discussion on the developers' mailing list.

comment:14 in reply to: ↑ 11 Changed 4 years ago by anonymous

  • Has patch unset
  • Needs documentation unset
  • Version SVN deleted

Replying to jacob:

I just can't come up with a use case that isn't something better done in a view or better done by just writing out the rows by hand. Besides, this is a pretty simple thing to add as a custom tag in your app.

This ticked is old, but to present you with a scenario that I'm into right now: I need to create a varying number of radiobuttons, depending of the number of choices allowed by the parents settings. The parent has a "number of objects allowed" field in the model. I therefore need to repeat a tag that can do the same thing {% for %}, but not iterating over an array or set, but just a variable number.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.