Django: how to display form errors for each model object in a inline formset
Solution 1
EDIT
authors_books_edits.html
<form method="post" action="/test/{{ author.id }}/books/">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset.forms %}
{{ form.non_field_errors }}
{{ form.errors }}
<table>
{{ form.as_table }}
</table>
{% endfor %}
<input type="submit" value="Submit"/>
</form>
views.py
from django.shortcuts import *
from django.forms.models import inlineformset_factory
from .models import *
def author_books_edit(request, author_id):
a = get_object_or_404(Author, pk=author_id)
authorsbooks = a.books_set.all()
bookformset = inlineformset_factory(Author, Books, can_delete=True, can_order=True, exclude=('company',), extra=1)
formset = bookformset(instance=a)
if request.method == "POST":
formset = bookformset(request.POST, request.FILES, instance=a)
if formset.is_valid():
formset.save()
else:
form_errors = formset.errors
return render_to_response('authors_books_edits.html', {'author': a, 'authorsbooks': authorsbooks, 'formset': formset, 'form_errors': form_errors}, context_instance=RequestContext(request))
return render_to_response('authors_books_edits.html', {'author': a, 'authorsbooks': authorsbooks, 'formset': formset,}, context_instance=RequestContext(request))
models.py
from django.db import models
class Author(models.Model):
fname = models.CharField(max_length=100)
lname = models.CharField(max_length=100)
def fullname(self):
return '%s %s' % (self.fname, self.lname)
fullname = property(fullname)
def __unicode__(self):
return self.fullname
class Books(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=50)
publisher = models.CharField(max_length=50)
edition = models.CharField(max_length=50)
comment = models.TextField()
def __unicode__(self):
return self.title
urls.py
from django.conf.urls.defaults import patterns, include, url
urlpatterns = patterns('testapp.views',
url(r'test/(?P<author_id>\d+)/books/$', 'author_books_edit'),
)
You can make another temporary app to test it.
It looks like this: http://imageshack.us/photo/my-images/824/screenshotat20120227190.png/
== END EDIT
You can iterate over forms as such:
{% for form in formset.forms %}
{{ form }}
{% endfor %}
In that case, refer to Django's displaying a form using a template documentation: https://docs.djangoproject.com/en/dev/topics/forms/#displaying-a-form-using-a-template
Then, more interesting, customizing a form template (see form.non_field_errors): https://docs.djangoproject.com/en/dev/topics/forms/#customizing-the-form-template
Solution 2
Assuming the book is a form you could do:
{% for b in authorsbooks %}
{{b.errors}}
{% endfor %}
Comments
-
thedeepfield almost 2 years
I have a author model and a books model. A user can modify properties of all the books from a given author. I want to be able to display errors for each individual book rather than have all the errors listed on the top, How can I do this?
MODELS
from django.db import models from django.forms import ModelForm, Textarea from django import forms class Author(models.Model): fname = models.CharField(max_length=100) lname = models.CharField(max_length=100) def fullname(self): return '%s %s' % (self.fname, self.lname) fullname = property(fullname) def __unicode__(self): return self.fullname class Books(models.Model): author = models.ForeignKey(Author) title = models.CharField(max_length=50) publisher = models.CharField(max_length=50) edition = models.CharField(max_length=50) comment = models.TextField() def __unicode__(self): return self.title
VIEW
def author_books_edit(request, author_id): a = get_object_or_404(Author, pk=author_id) authorsbooks = a.books_set.all() bookformset = inlineformset_factory(Author, Books, can_delete=True, can_order=True, exclude=('company',), extra=1) formset = bookformset(instance=a) if request.method == "POST": formset = bookformset(request.POST, request.FILES, instance=a) if formset.is_valid(): formset.save() else: form_errors = formset.errors return render_to_response('test/authors_books_edits.html', {'author': a, 'authorsbooks': authorsbooks, 'formset': formset, 'form_errors': form_errors}, context_instance=RequestContext(request)) return render_to_response('test/authors_books_edits.html', {'author': a, 'authorsbooks': authorsbooks, 'formset': formset,}, context_instance=RequestContext(request))
TEMPLATE
#all errors are here {% for dict in form_errors %} {{ dict }} {% endfor %} #all forms are here, i want to pair the errors for each form <form method="post" action="/test/{{ author.id }}/books/"> {% csrf_token %} <table> {{ formset }} </table> <input type="submit" value="Submit"/> </form>
UPDATED TEMPLATE: doesn't display errors
<form method="post" action="/test/{{ author.id }}/books/"> {% formset.management_form %} {% csrf_token %} <table> {% for x in formset %} {{x.errors }} {{ x }} {% endfor %} </table> <input type="submit" value="Submit"/>
-
thedeepfield about 12 yearsi updated my template but now i get an error and the page is broken... I've updated my post to include the updated template.
-
Nix about 12 yearsWhat did the debug output say?
-
thedeepfield about 12 yearsit says ValidationError [u'ManagementForm data is missing or has been tampered with']
-
thedeepfield about 12 yearsfor some reason my errors are still not showing up. I've updated my template. what am I doing wrong?
-
jpic about 12 yearsDid you try {{ x.non_field_errors }} instead of {{x.errors }} ?
-
thedeepfield about 12 yearsyes, x.non_field_errors does not show anything. It's weird because {% for dict in form_errors %} {{ dict }} {% endfor %} shows errors, just not in pair with my forms...
-
jpic about 12 yearsThere are two kinds of errors: field errors and non field errors. To get field errors, which should display next to the inputs, use {{ form.field_name.errors }}. To get non field errors, which should display at the top of the form, call {{ form.non_field_errors }}
-
thedeepfield about 12 yearsthanks for your input but the errors are still not appearing.. I put {{ form.non_field_errors }} right under {{ form.management_form }}, I also put {{ x.nameofmyfield.errors }} right above {{ x }} and nothing showed up.. what am I doing wrong? this is driving me nuts.
-
jpic about 12 yearsI got an update which might do what you want. If it doesn't, please elaborate a description of the result you want (pseudo-html ?)
-
jpic about 12 yearsThis is because: docs.djangoproject.com/en/dev/topics/forms/formsets/…