how to display form data with original values after validation failure?

2,567 views
Skip to first unread message

snfctech

unread,
Jun 21, 2011, 8:35:56 PM6/21/11
to Django users
In the case of editing a form, I want to display the original value of
a field prior to validation failure, as well as the validation
errors. This doesn't seem to work:

if fs.is_valid():
fs.save()
else:
# return original data - not default changed data
errors = fs._errors
q =
JosJeventsRegistration.objects.using('default').filter(user=user,
status='cart')
fs = RegistrationFormSet(queryset=q)
fs._errors = errors

Context:

For my UI on a class registration shopping cart, a user can edit the
number of guests. Some classes have limited availability for certain
roles - e.g. there may only be 2 spaces available, so the user can
only enter 2 guests (including themselves). The current error
messaging says "There are only x more spaces available for this
role." If the user already had 1 guest and then enters 4 guests, then
it's unclear how many spaces the user can enter to correct the error
unless they remembered the original value. I think it would be more
straight forward if the form reset to its original values and
displayed the error.

Any tips on how to best accomplish this would be greatly appreciated.

Shawn Milochik

unread,
Jun 21, 2011, 8:44:20 PM6/21/11
to django...@googlegroups.com
One good way is to just use AJAX: If it's a 'get' request, return your
rendered template as normal. If it's a 'post' request, return a JSON
response that has a success/failure status and confirmation/error
messages (form.errors.as_text()).

I'm doing this using jquery-notify to tell the user that it went great
or what the problem was:
http://www.erichynds.com/examples/jquery-notify/

If you need to redirect or refresh the page on success you can handle
that with JavaScript as well. In addition to being faster than a
full-page refresh this happens to solve your problem.

Shawn

snfctech

unread,
Jun 21, 2011, 8:58:07 PM6/21/11
to Django users
Thanks for your reply, Shawn.

I'll think about that - but I think I would prefer to use more boiler-
plate Django form behavior and just get a formset with errors returned
to my template in the full-page response.

Kevin Renskers

unread,
Jun 22, 2011, 4:14:54 AM6/22/11
to django...@googlegroups.com
If I understand this correctly, then you want something like this?

1) Show a form to edit something
2) User changes fields, submits the form
3) If the form was not valid, not only show the errors and the form with the entered values, but also the *old* values, pre-edit.

I think your best bet is to create custom valid_field() validation functions in the form class, which access the form instance to show the old values in the error message.

snfctech

unread,
Jun 22, 2011, 4:44:27 PM6/22/11
to Django users
Hi, Kevin. Thanks for your reply.

I actually don't want to show the entered values - I basically want
the original form with values prior to the user submitting the form -
but with the validation errors that prompt them to enter new values in
the proper fields. I have already overridden the particular field's
clean method (clean_guests), but I don't understand how to preserve
the field's original value.

class RegistrationForm(ModelForm):
guests = forms.IntegerField(error_messages={'invalid': 'Please
enter a number greater than zero.'})

# enforce role/price limits
def clean_guests(self):
data = self.cleaned_data['guests']
if self.instance.price.parent.price_limit:
spaces_available = self.instance.price.spaces_available
delta = data - self.instance.guests
if delta > 0:
if spaces_available == 1 and delta > 1:
print self.instance.guests
raise forms.ValidationError("There is only 1 more
space available for this role.")
elif spaces_available > 1 and delta >
spaces_available:
raise forms.ValidationError("There are only %s
more spaces available for this role." % spaces_available)
else:
raise forms.ValidationError("Sorry, there are no
more spaces available for this role.")

return data

class Meta:
model = JosJeventsRegistration
fields = ['id', 'guests']

My view creates the form with the POST data in the standard fashion:

if request.method == 'POST':
fs = RegistrationFormSet(request.POST)
if fs.is_valid():
...

Which passes the form with the same post data and some error messages
back to the user.

Michał Sawicz

unread,
Jun 22, 2011, 4:59:24 PM6/22/11
to django...@googlegroups.com
Dnia 2011-06-22, śro o godzinie 13:44 -0700, snfctech pisze:

> Which passes the form with the same post data and some error messages
> back to the user.

Maybe you could just reinstantiate a clean RegistrationFormSet without
passing request.POST to it? Maybe copying errors from the original,
bound one.

Just my c2.

Cheers
--
Michał (Saviq) Sawicz <mic...@sawicz.net>

signature.asc

snfctech

unread,
Jun 22, 2011, 5:50:47 PM6/22/11
to Django users
Hi, Michal.

I tried that, but the errors don't get rendered for some reason (see
my first post).

Tony
>  signature.asc
> < 1KViewDownload

snfctech

unread,
Jun 22, 2011, 7:33:37 PM6/22/11
to Django users
Figured it out - you have to populate both fs._errors _and_ loop
through each form in the formset and populate its _errors attribute,
as well.
Reply all
Reply to author
Forward
0 new messages