Django: display text between form fields - django

Hi Stackoverflow people,
I am displaying a large form through a loop:
<table>
{% for field in projectDetailForm %}
<tr>
<td> {{ field.label_tag }} </td>
<td> {{ field }} </td>
</tr>
{% endfor %}
</table>
I would like to interrupt the table with the form fields after a few form fields to display more explanations. Since the form is fairly large (20 fields), I would like to avoid the "manual display" of each form field (as described here).
Is there a way to display the text form within the loop, either after the x-th loop or after a specific form field?
Thank you for your advice!

I would either use forloop.counter or set a custom attribute on a form field on form initialization and display the attribute the same way you display field.label_tag

You can add a method to your form, which will return fields by portions. Something like:
def by_5(self):
iterable = iter(self)
zipped = zip(*([iterable] * 5)) # replace 5 by desired n
for z in zipped:
yield z
remained = list(iterable)
if remained:
yield remained
Then in template:
<table>
{% for fields in projectDetailForm.by_5 %}
{% for field in fields %}
<tr>
<td> {{ field.label_tag }} </td>
<td> {{ field }} </td>
</tr>
{% endfor %}
<tr><td colspan="2">Hi there!</td></tr>
{% endfor %}
</table>

There is a {{ forloop.counter }} and {{ forloop.counter0 }} (1-indexed and 0-indexed respectively) that you can use.
For a few more information, check this Djangobook link.

Related

Django hidden input being rendered as <td> in html

I'm using a modelformset to allow the user to add/edit/delete food item's on their restaurant's menu.
FoodItemFormset = modelformset_factory(FoodItem, fields = '__all__', can_delete = True)
I'm then iterating over all of the forms in my template and displaying them in a table:
<table>
<tr>
<th>Food Item</th>
<th></th> <!-- empty <th> lines up with hidden input field -->
<th>Delete</th>
</tr>
{% for form in food_formset %}
<tr>
{% for field in form %}
<td>{{ field }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input type="submit" name="" value="Submit">
However, that can_delete attribute does not only lead to a checkbox being rendered, it also renders the hidden field containing the object's id as an actual table element, leading to an empty gutter between the tables contents.
<td><input type="text" name="form-0-name" value="Mozzarella Sticks" maxlength="200" id="id_form-0-name"></td>
<td><input type="hidden" name="form-0-id" value="2" id="id_form-0-id"></td> <!-- this just looks like an empty gutter -->
<td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE"></td>
Is there a way to get around this? Thanks for any help.
Loop over form.visible_fields to only include visible fields.
{% for field in form.visible_fields %}
<td>{{ field }}</td>
{% endfor %}
You will also need to render the hidden fields but this doesn't need to be in it's own table cell.
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}

Django template tags - arrange result of queryset

I am trying to format my results in a table.
<tr>
<td>A6</td>
<td>A6 title</td>
<td>
{% for record in a6titles %}
titles: {{ record }}
{% endfor %}
</td>
</tr>
The data displays in a single row. I would like each result item to be displayed in its own row. I am sure this is very simple; however, I am very new to this.
# You need to put your tr tag in for loop
{% for record in a6titles %}
<tr>
<td>A6</td>
<td>A6 title</td>
<td>titles: {{ record }}</td>
</tr>
{% endfor %}

cant get an id to be added to a django formset

im getting an error when trying to POST a form, which doesn't make much sense.
the error:
MultiValueDictKeyError at /admin/courses/course-selector/add/
"Key 'form-0-id' not found in <QueryDict:
so i've done the googling and worked out that because i'm drawing the form myself (I'd built a table and printed out each field in the place i wanted it).
so I've tried to add in a field with the id and it doesn't print. it just doesn't have an id in the template for me to write into the form. im not sure what to do now cos the established advice for this case in google i've followed and found an issue.
the template code.
<form action="." method="POST" id="formset">
<table>
<tr>
{{ formset.management_form }}
</tr>
<tr>
<th></th>
{% for field in formset.forms.0 %}
{% if not field.is_hidden %}
<th>{{ field.label }}</th>
{% endif %}
{% endfor %}
</tr>
{% for f in formset.forms %}
<tr>
<td><input type="checkbox" id="checkbox_{{ f.id }}" /></td>
<td>{{ f.id }}</td>
{% for field in f %}
{% if not field.is_hidden %}
<td>
{{ field.errors }}
{{ field }}
</td>
{% else %}
<td valign="bottom">{{ field }}</
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</table>
</form>
snipped for brevity...
why doesn't {{ f.id }} output anything.
edit1
adding in the code that generates the formset, it might be why im not getting an id.
InstanceFormSet = formset_factory(BulkAddInstanceForm, extra=0)
# build the list for populating the forms
n, datalist = 0, []
while n < int(input_data['copies']):
datalist.append(data)
n +=1
formset = InstanceFormSet(initial=datalist)
i've found multiple errors in your template:
you are iterating over all forms in the formset but you are also displaying all non hidden fields of the first form. this means you have duplicated fields
later you are iterating over all fields in all forms. but you are also displaying the id field twice. once as a field and one as part of the checkbox id. if the form doesn't have an id field it does not output anything as f.id
I use {{forloop.counter0}} or {{forloop.counter}}
to work out what the id for the form in the formset should be
A few years late to the game, but this is the answer. Put this under {% for f in formset.forms %}
{{ forloop.counter }}
This will output the number associated with each form (eg. 1, 2, 3, etc.)

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!
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 %}
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>
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>
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.
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 %}

Django: Aquiring form id from formset

I am not sure if title describes what i want accurately. What i want is to achieve something like that: Django add / remove form without multiple submit.
But i have not list of items i have formset and forms. The form of this formset does contain information i could use for creating link like that {% url 'item_edit' item.id %}. The problem is that it is a value of an hidden field. Here (http://docs.djangoproject.com/en/dev/topics/forms/#looping-over-the-form-s-fields) you have a list of options how to use fields of a form in a template, but none of them is {{ field.value }}. If i tried that, then it just failed silently.
Anyway. to the code. What i have in template is:
<form enctype="multipart/form-data" method="post" action="/list/edit/{{ list.id }}/">
<table>
{{ form.as_table }}
{{ formset.management_form }}
{% for form in formset.forms %}
{% if forloop.first %}
<tr>
{% for field in form.visible_fields %}
<td>{{ field.label }}</td>
{% endfor %}
</tr>
{% endif %}
<tr>
{% for field in form.visible_fields %}
{% if not forloop.last %}
<td>{{ field }}</td>
{% else %}
<td>{{ field }}
{% endif %}
{% endfor %}
{% for field in form.hidden_fields %}
{% if not forloop.last %}
{{ field }}
{% else %}
{{ field }}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
<tr><td><input type="submit" value="Submit"></td><td colspan="4"> </td></tr>
</table>
</form>
And this gives me inline form rows like this:
<tr>
<td><input type="text" maxlength="200" value="test2" name="shoppinglistitem_set-0-itemname" id="id_shoppinglistitem_set-0-itemname"/></td>
<td><input type="text" maxlength="200" value="http://www.xxx.ee" name="shoppinglistitem_set-0-link" id="id_shoppinglistitem_set-0-link"/></td>
<td><input type="text" maxlength="100" value="eepöäsdöäfsdfd" name="shoppinglistitem_set-0-store" id="id_shoppinglistitem_set-0-store"/></td>
<td><input type="text" id="id_shoppinglistitem_set-0-price" value="22134" name="shoppinglistitem_set-0-price"/></td>
<td><input type="checkbox" id="id_shoppinglistitem_set-0-DELETE" name="shoppinglistitem_set-0-DELETE"/><input type="hidden" id="id_shoppinglistitem_set-0-list" value="1" name="shoppinglistitem_set-0-list"/><input type="hidden" id="id_shoppinglistitem_set-0-listitem_ptr" value="5" name="shoppinglistitem_set-0-listitem_ptr"/></td>
</tr>
and i am looking for some way to add link like this
<a href={% url 'remove_list_item' item.id %}>REmove</a>
or just
REmove
Urlconf for this view is:
url(r'^removeitem/(?P<lisitem_id>\d+)/$', 'remove_list_item', name='remove_list_item')
So is there some easy way to get that id of the item(object) from the form? Do i have to create some kind of widget for that remove link instead?
Alan.
First of all, you shouldn't use links (GET requests) to trigger actions that edit or delete data, you should use POST requests.
You can still use a link to delete data by creating one via JavaScript and using their click-Event to make an Ajax POST request. With JavaScript you can also easily read the id from the hidden field. If your form should be usable without JavaScript (and it should), then you should create another form for deleting items (probably just a delete button).
You should use a form for deleting, because for Djangos CSRF-Middleware to work you need forms. And CSRF-Middleware should be in your middleware stack.
If you initialize a Django Form with an object, as you probably have, the fields of the objects are stored in a dictionary called initial. You might be able to access it via form.initial["id"] or in template speak {{ form.initial.id }}, though I am not sure if it works or if it's a good idea.
The for loop you are using in the template can also handle lists of lists or tuples as well as simple lists so the solution I use to this problem, mixing display and formset elements, is to create a list of tuples in my view. Each tuple is (form, data)
I then pass this mixed list of forms and data to the template rather than simply the formset
The outer for loop in your template then becomes
{% for form, data in forms_and_data_list % }
{% endfor %}
you can then display the data part, in your case the edit url, just as you would normally.