cant get an id to be added to a django formset - django

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.)

Related

How to loop through crispy fields

How can I arrange my form in a table?
I had a normal form and I was arranging it in my template like this.
<table border="0" >
{% for field in form %}
<tr >
<td>
<label for="{{ field.label }}">{{ field.label_tag }}
{% if field.field.required %}<span style="color:red"; class="special_class">*</span>{% endif %}</label>
</td>
<td>
{{ field }}
</td>
</tr>
{% endfor %}
</table>
Now I want to use crispy forms. but couldn't figure out how to display my form.
of cause it has works with this.
{% load crispy_forms_tags %}
{% crispy form %}
but that was not arranging my fields well,
how can I access these fields by a loop?
Any help would be greatly appreciated.
You can iterate over fields and then use crispy like this:
{% for field in form %}
{{ field|as_crispy_field }}
{% endfor %}

(How) can I tell if my form field is hidden in Django template

I have a Django model formset, and some fields have hidden inputs.
I am trying to generate the headings from the first item in the formset with formset.visible_fields. This works.
<table>
<tr>
{% for myfield in formset.0.visible_fields %}
<th> {{ myfield.name }}</th>
{% endfor %}
</tr>
{%for form in formset %}
<tr>
{% for field in form %}
<td>{{ field }}</td>
{% endfor %}
</tr>
{% endfor%}
</table>
The problem is that the hidden fields don't get a heading. But when I am iterating through my form fields, the hidden field is still getting wrapped with a tag. So I get a column for every field, but a heading for only the visible fields.
Is there a way to check in advance if my field is hidden?
(Or is there a better way to hide the headings / fields?)
Hidden fields do have a property. Here's the docs about them.
Code from the docs:
{# Include the hidden fields #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{# Include the visible fields #}
{% for field in form.visible_fields %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
If you have to work only with a field, for example, a field named foo, you can easily check if is visible in the template.
{% if form.foo.is_hidden %}
{# render the field here #}
{% else %}
{# do something here you need if the field is visible #}
{# render the field here #}
{% endif %}

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: display text between form fields

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.

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.