neurix
neurix

Reputation: 4316

Django/Python: Loop over selected form fields in Django template

I have a form with n fields. The first 4 fields should be displayed differently in my template then the rest of the form. Therefore, I was wondering if I can somehow loop over the first 4 fields, end the loop and continue looping over the rest of the fields later in the template.

        <table>
            {% for field in form %}
            {% if forloop.counter == 4 <<< Break here >>>%}
            <tr>
                <td> {{ field.label_tag }} </td>
                <td> {{ field }} </td>
            </tr>
            {% endfor %}
        </table>
        .... Different code ....
        <table>
            {% for field in form %} <<< Continue here >>>
            <tr>
                <td> {{ field.label_tag }} </td>
                <td> {{ field }} </td>
            </tr>
            {% endfor %}
        </table>

I have found this code but I was wondering if I could structure the template differently or if I have missed some new changes in Django 1.3 which allow the breaking of loops now.

Normally, I would split the form in two seperate forms, but I would like to reuse the form definition in other templates as well, therefore I would like to keep all information together in one form.

Thank you for your advice!

Upvotes: 1

Views: 7373

Answers (5)

Gajush
Gajush

Reputation: 66

Shorter than "Yuji 'Tomita' Tomita" answer

Make list for form on your view:

context = {'form': list(form)}
return render(request, template, context)

and get each field on template by |slice

{% for field in form|slice:":4" %}
    <tr>
        <td> {{ field.label_tag }} </td>
        <td> {{ field }} </td>
    </tr>
{% endfor %}

Upvotes: 0

Ramon de Jesus
Ramon de Jesus

Reputation: 788

Since form is a list, you could also use Django's built-in slice template filter: https://docs.djangoproject.com/en/1.3/ref/templates/builtins/#slice

Your example would become:

    <table>
        {% for field in form|slice:":4" %}
        <tr>
            <td> {{ field.label_tag }} </td>
            <td> {{ field }} </td>
        </tr>
        {% endfor %}
    </table>
    .... Different code ....
    <table>
        {% for field in form|slice:"4:" %}
        <tr>
            <td> {{ field.label_tag }} </td>
            <td> {{ field }} </td>
        </tr>
        {% endfor %}
    </table>

Upvotes: 2

It's the same solution as other "can't do it in the template" problems: do it in the view. I truly believe added complexity and further separation of logic into multiple code areas (tags, new files, etc.) only hurts maintainability. I separate / implement DRY only when things actually do get repetitive, unreadable, etc.

Everything else is premature optimization.

Django won't know the difference when a form is submitted.

fields = list(form)    
part1, part2 = fields[:4], fields[4:]


{% for field in part1 %}{{ field }}{% endfor %}
...
{% for field in part2 %}{{ field }}{% endfor %}

Upvotes: 8

c4urself
c4urself

Reputation: 4287

You're almost there, if you just add

<table>
{% if forloop.counter <= 4 %}
... first four fields
{% else %}
... other fields
{% endif %}

If you need two different tables you could add:

{% if forloop.counter == 1 %}
<table>
{% endif %}

{% if forloop.last %}
</table>
{% endif %}

That's not a very pretty solution, but it works. You could also consider using two forms.

Upvotes: 1

Gevious
Gevious

Reputation: 3252

I would suggest you write your own custom template. Perhaps your filter could look like this:

def show_part(form,section=1): 
    display = ''
    for id,field in enumerate(form):  
         if int(section) == 1 and id > 3:
             break
         elif int(section) == 2 and id < 3:
             continue
         display += '<tr><td>'+field.label_tag+'</td>'
         display += '<td>'+field+'</td></tr>'
    return display    

and use the following in your template:

<table>
    {{ form|show_part:"1" }}
</table>
<table>
    {{ form|show_part:"2" }}
</table>

Upvotes: 2

Related Questions