I have a good bit of experience in non-Django web development, but I am struggling to find a good practice for handling what to do when the user enters invalid data in their form and I want to re-display the form with their submitted data and the form errors displayed as well. I have a simple form with three fields and this is how I finally made it work.
def get(self, request) :
# Check if we have been redirected...
redirect_html = request.session.pop('form_error_html', False)
if redirect_html : return HttpResponse(redirect_html)
old_data = {'title': 'SakaiCar', 'mileage' : 42,
'purchase_date': '2018-08-14' }
form = BasicForm(initial=old_data)
ctx = {'form' : form}
return render(request, 'form.html', ctx)
def post(self, request) :
form = BasicForm(request.POST)
if not form.is_valid() :
ctx = {'form' : form}
html = render_to_string('form.html', ctx, request=request)
request.session['form_error_html'] = html
return redirect(request.path)
# Do something with the valid data..
return redirect('/')
My template is really basic (I like this simplicity):
<p>
<form action="" method="post">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit">
</form>
</p>
Now this approach kind of weirds me out because I am sending the entire rendered HTML page through the session from the post()
to the get()
. But I can't send the form
with the errors in place through the session back to the the get()
(that would be prettier) because it won't serialize - you get "Object of type 'BasicForm' is not JSON serializable".
I have done this a different way where I extract the errors form the form
object into a list
and then pass my own list of errors from the post()
to the redirected get()
and then alter form.html
to display errors.
{% if errors %}
{% for error in errors %}
<p style="color:red">Error in {{ error.label }}: {{ error.message }}</p>
{% endfor %}
{% endif %}
I have not included all the Python code to make this work - but you get the idea. This feels more elegant because I am not putting a blob of HTML into the session, but then the errors display in a way other than the normal Django forms way. And if I were using crispy forms - then all that crispy UI goodness would not come into play.
I even thought about pulling out the errors in the post()
code and passing them to the get()
through the session and then inserting them into the form
object in the get()
prior to render()
- that would feel more elegant too. If I get bored I might try to dig through the forms structure and implement this as well.
I just cannot believe that with Django having so mush awesome built-in magic - that I can't just say something like return form.post_redirect_get()
in the not form.is_valid
code.
I want something that is a replicable pattern that is easily explained and used the Django UI elements as much as possible.
To create such an error, you can raise a ValidationError from the clean() method. For example: from django import forms from django. core.
Django provides built-in methods to validate form data automatically. Django forms submit only if it contains CSRF tokens. It uses uses a clean and easy approach to validate data. The is_valid() method is used to perform validation for each field of the form, it is defined in Django Form class.
GET and POSTDjango's login form is returned using the POST method, in which the browser bundles up the form data, encodes it for transmission, sends it to the server, and then receives back its response. GET , by contrast, bundles the submitted data into a string, and uses this to compose a URL.
You're misunderstanding. You're only supposed to redirect after a successful post. On a post that fails validation, you don't redirect at all, you redisplay the invalid form - whichwill show the validation errors.
form = BasicForm(request.POST)
if form.is_valid()
return redirect ("/")
else:
ctx = {'form' : form}
return render(request, "template.htnl,", ctx)
Note, a FormView will handle all this for you; you shouldn't have to define post
or get
methods at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With