data How to keep form when user gets redirected back to the form when they fail a validation (Python, Django)? - django

I know this might be a duplicate question, but the previous one was an older question and those questions uses a form instance which doesn't really help me.
How do I keep my form data after a failed validation? I have multiple dropdowns and input fields and I hate to see my users re-do and re-type everything when they fail validation in the backend. Let's say I have this very simple form:
HTML:
<form class="" action="/register" method="post">
<label for="">First Name</label>
<input type="text" name="" value="">
<label for="">Last Name</label>
<input type="text" name="" value="">
<label for="">Password</label>
<input type="password" name="" value="">
</form>
views.py:
def register(self):
.....
if errors:
for err in errors
messages.errors(request, err)
return redirect('/')
else:
messages.success(request, "Welcome User!")
return redirect('/dashboard')
Most examples that I came across were using the form instance which uses form.save() etc. I opted out on that one. Is there a way to auto-populate my form with the data that the user submitted if they were to fail validation? Thanks!

Django form classes are the way to go. Form validation and rendering are the tasks they were build for. I would strongly recommend using them, because they also take care of security aspects, when it comes to passing user input back to the browser (all input from user land is evil!).
If you really need to achieve this without form classes, you need to add the form values to your rendering context manually - this allows you to use them in your template.
The main problem with your approach is, that you want to redirect in case of validation error. A redirect is a response to the browser that tells: I have nothing for you, please go to this location. Usually the browser does not post the data send in the first request also to the second one (which is generally a good behavior). You may work around that by answering with status code 307 instead of 302. Read e.g. Response.Redirect with POST instead of Get? for more information. Alternatively you may encode your form data into the target location using get parameters.
Again: You should have a very good reason to not just use the django approach of one view that acts on GET and POST different and handles the form properly using the form instance.

Related

django redirect after post with post parameters after update

I was looking for help but couldn't find any suitable solution.
I would like to ask about redirect after POST.
Situation looks as below step by step:
Simple search form with POST with parameter called 'find' within form. Search form appears on every site and if i call search on site with devices i'm checking referrer and i'm doing query for device model fields and results go to devices.html template. Same situation is when I search within localization site, checking for referrer and querying for model fields of localization model and returning query result in localization.html template.
When I try to update device i'm opening new edit device template with url '/edit/device/dev_id' when every field of this model is shown so i can update some fields manually.
After commiting changes on edit site device 'post' goes to url 'update/device/dev_id' and changes to device are saved properly.
The problem is how can I redirect after updating device to step number one where are the results of search view for devices?
If i redirect after update ('update/device/dev_id') device to 'request.META.get('HTTP_REFERER')' i'm getting 'edit/device/dev_id' url ?
Worth to mention is that method POST for search form sends text search input to action="/search" and then after checking referrer shows results, so there is nothing like 'action="search/find".
I know that in web browser we can do few times previous click to show search results incuding POST parameters but it is not the point.
If you have any ideas how to redirect to search results (method POST, 1 point) after updating please let me know.
Regards AD
I will try to simplify the question ( too much code to paste ):
Given search below in template:
<form class="navbar-form navbar-left" action="/search" method="post">{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control" name="find" placeholder="Search">
</div>
<button type="submit" class="btn btn-default" >Search</button>
</form>
in views.py:
def search_dev(request):
to_find=request.POST.get('find')
(..)
<--query updating_fields in instance considering only 1 search result-->
redirect ? (to search query with POST )
Is it possible to go back to search results after some changes to instance ( for example update ) considering only 1 search result ?

Form Validation On Frontend or Backend Django

I have an HTML form with a date field:
<input type="date" class="form-control" placeholder="Date" name="date" autocomplete="off" required>
Before submitted the form, I want to ensure that the date that was entered is greater than the current date. If it is older, then I want to show a custom form validation to say something like, "You must enter a date past today.".
Do you suggest I do this validation on the backend or the frontend? Thanks!!
I think you're better off doing in within django forms. The reason is, if you do it in the front-end, you'll have to repeat the code when applying this property elsewhere.

How do I pass multiple variables from one handler to another in GAE?

I want to redirect users to a confirmation page that will display both subject and content (if there is any) if they enter a valid subject, but stay on the same page and display an error if the subject is either blank or over three hundred characters.
Here is my backend code:
def post(self):
subject = self.request.get('subject')
content = self.request.get('content')
a, b = self.validSubject(subject)
if a == True and b == True:
self.redirect('/confirm')
else:
if a == False:
error = "Title cannot be blank!"
if b == False:
error = "Title cannot be over 300 characters."
self.render("newpost.html", subject = subject, content = content, error = error)
Here is the code for the newpost.html template:
<h2>New Question</h2>
<hr>
<form method="post">
<label>
<div>Title</div>
<input type="text" id="subject" name="subject">
</label>
<label>
<div>
<textarea name="content" id="postcontent"></textarea>
</div>
</label>
<b><div class="error">{{error}}</div></b>
<input type="submit">
</form>
I've tried adding action="/confirm" to the POST form, but that redirects to /confirm even if there is an error. I've looked at the webapp2 documentation but couldn't find anything on how to pass variables on a redirect. (https://webapp-improved.appspot.com/api/webapp2.html#webapp2.redirect)
I'm using webapp2 and jinja2. Thanks for any help in advance, I've been looking at this piece of code for quite a while :(
The pattern you're trying to write doesn't work within http, irrespective of what backend platform or language you're using. Your HTML is posting to the server and the GAE code is handling the post. At that point in the interaction, the browser has already submitted and is awaiting a response from the server. You can't stop the submission at that point since it's already happened.
You should consider validating the input in Javascript before the form is even submitted to the server. That way you can suppress the submission of the form in the first place if your data isn't valid.
Take a look at the following question to see an example of this:
JavaScript code to stop form submission

Form action and its usage in Django

First Quesiton:
This form submits to demo_form?name=ABC
<form action="demo_form" method="get">
name: <input type="text" name="name"><br>
<input type="submit" value="Submit">
</form>
Is there a way to make it submit to demo_form/ABC/?
Second Question:
Even if users don't use my form, if they use a web crawler to simply visit demo_form?name=ABC or demo_form/ABC/, it would yield the same result. I want to prevent that. What's the best way of making those two URLs only valid if the user submit the name via my form? I am learning django so hopefully the solution would work with django framework.
Thanks in advance!
Is there a way to make it submit to demo_form/ABC/?
You could intercept the submission in JavaScript, construct the URL manually, then set location. That would break if JS wasn't available.
More sanely, you could send an HTTP 301 redirect response when you get the request for demo_form?name=ABC
What's the best way of making those two URLs only valid if the user submit the name via my form?
Generally speaking, visiting a form should not be a pre-requisite for anything involving a GET request. A large portion of the point of GET is that the results are bookmarkable, linkable, etc.
It would be more understandable if it was a POST request, as those are intended to change data on the server and you will want to protect against CSFR. The standard protection against CSRF is a token stored in the form and in a cookie

Redirect to views according to form selection

User registration in my application is performed in steps. After submitting the form, some validation is performed and then register_prompt view is called. It renders a form, with two options - 'ok' and 'cancel'. Clicking ok will run registration, and clicking cancel should redirect to main page. Problem is that no matter which of the two I choose, I'm redirected to .../user/registration/function_1_or_2_name with a blank page (although I have specified url in HttpResponseRedirect ). How can I make it work ?
def register_prompt(request):
context = RequestContext(request)
return render_to_response('user/data_operations/alert.html', context_instance=context)
Form loaded on alert.html :
<form action="" method="post">
<input type="submit" class="submit" name="submit" onClick="this.form.action='{% url register_new %}'" value="Ok" />
<input type="submit" class="submit" name="submit" onClick="this.form.action='{% url redirect_home %}'" value="Cancel" />
</form>
Redirect views (maybe there is a better way to do that ?):
def redirect_home(request):
return HttpResponseRedirect('/')
def register_new(request):
(... registration magic here ...)
return HttpResponseRedirect('/user/registration/complete/')
Finally url conf :
url(r'^register_new/$', register_new, name="register_new"),
url(r'^redirect_home/$', redirect_home, name="redirect_home"),
url(r'^register_prompt/$', register_prompt, name="register_prompt"),
At first I was trying to add some abstract values to form's buttons (like 'action=ok'), and then catch them in register_prompt but it was a total disaster.
I'm not sure if that onClick="" hack is really valid (I'll let someone else weigh in on that), but did you try just using normal links, to see if it's that or something else?
OK
Cancel
(Or check out <button> if you really want it to look like buttons. Or just use two <form>s, each with a separate action="" attributes.)
Hum, other than that... You say ".../user/registration/function_1_or_2_name" -- what exactly does the {% url .. %}s give you? Does it not add the final / (which you require in your patterns)?
At first I was trying to add some
abstract values to form's buttons
(like 'action=ok'), and then catch
them in register_prompt but it was a
total disaster.
But you seem to want to manipulate the action attribute, so you can't catch anything in register_prompt()?
All in all I'd suggest you either use normal links, or actually handle the POST in the view that presented it:
def register_prompt(req):
if 'ok' in req.POST:
return register_new(req)
if 'cancel' in req.POST:
return register_cancel(req)
return render_to_response('user/data_operations/alert.html',
context_instance=RequestContext(req))
Maybe something like that? Renaming your buttons to ok and cancel, and having the form post back to itself...