Flask - difference between methods for detecting 'POST'? - flask

When i want to check if form data was submitted using POST, what is the difference between:
if request.method == 'POST'
And:
if form.validate_on_submit():
?

form.validate_on_submit() does what the request.method == 'POST' and more, so it's like a more advanced function.
form.validate_on_submit() is a function implemented in the "Flask-WTF" package, which is a shortcut to two functions: form.is_submitted() and form.validate()
def validate_on_submit(self):
"""Call :meth:`validate` only if the form is submitted.
This is a shortcut for ``form.is_submitted() and form.validate()``.
"""
return self.is_submitted() and self.validate()
Note: The self.validate() is implemented by the "wtforms" package, which "Flask-WTF" uses the wtforms.Form as a base class for the flask_wtf.FlaskForm or the flask_wtf.Form which is deprecated.
Going deeper, what the self.is_submitted() function does is return a _is_submitted() boolean function:
def is_submitted(self):
"""Consider the form submitted if there is an active request and
the method is ``POST``, ``PUT``, ``PATCH``, or ``DELETE``.
"""
return _is_submitted()
And the _is_submitted() is defined as:
def _is_submitted():
"""Consider the form submitted if there is an active request and
the method is ``POST``, ``PUT``, ``PATCH``, or ``DELETE``.
"""
return bool(request) and request.method in SUBMIT_METHODS
The SUBMIT_METHODS constant is defined this way:
SUBMIT_METHODS = set(('POST', 'PUT', 'PATCH', 'DELETE'))
From the snippets, you can see that the form.validate_on_submit() handles the request.method and does more.
So if you are making use of the Flask-WTF package and your form is inheriting from the "FlaskForm" class, it's better to use form.validate_on_submit() than request.method == 'POST', as the former handles both verifying if a form is submitted and if the post request made is also valid.

Related

Should my forms in django be processed in a different view than the one that serves them?

Is it okay to have a view that both serves the form and processes the form's action?
For example:
if request.method == 'POST':
(process form)
else:
serve form
Would it be better practice to add an action parameter to the form and redirect to a view specifically for processing the form?
Yes, that's the way to go (you don't need a else statement though). Django and other frameworks do this - the assumed default is GET, then you add a if statement for the POST method.
Don't forget to return a redirect response in case you don't want the form to be reposted. Also, if the form processing is long - you can use a separate method / service. Something like:
def my_view(request):
form = SomeForm(data=request.POST or None)
if request.method == 'POST':
if form.is_valid():
do_something(form) # form processing that could save a couple of objects, send notifications, etc.
messages.success(request, "Some message.")
return HttpResponseRedirect(request.path)
return render(request, ".../template.html", locals())
This way, you keep the business logic separated and you can easily unit test it (in this example, you would unit test do_something(...)).
Yes, this is ok. This is what Django does normally. Note that the generic FormView has got get andpost methods.
(To understand how they're called, read the dispatch method.)

What does request.method == "POST" mean in Django?

I am using this thing in my views quite a lot but I want to know what exactly does that mean.
What happens when we write request.method == "GET" or request.method == "POST"?
The result of request.method == "POST" is a boolean value - True if the current request from a user was performed using the HTTP "POST" method, of False otherwise (usually that means HTTP "GET", but there are also other methods).
You can read more about difference between GET and POST in answers to the question Alasadir pointed you to. In a nutshell POST requests are usually used for form submissions - they are required if processing a form would change server-side state (for example add user to a database, in case of a registration form). GET is used for normal HTTP requests (for example when you just type an URL into your browser) and for forms that can be processed without any side-effects (for example a search form).
The code is usually used in conditional statements, to distinguish between code for processing a submitted form, and code for displaying an unbound form:
if request.method == "POST":
# HTTP Method POST. That means the form was submitted by a user
# and we can find her filled out answers using the request.POST QueryDict
else:
# Normal GET Request (most likely).
# We should probably display the form, so it can be filled
# out by the user and submitted.
And here is another example, taken straight from Django documentation, using Django Forms library:
from django.shortcuts import render
from django.http import HttpResponseRedirect
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render(request, 'contact.html', {
'form': form,
})
request.methodreturns the type of the request method it may be GET,POST,PUT,DELETE etc.
after returning you are comparing it with your string.
comparison operator always provides a boolean value(True or False).
Some times we need to handle the functionality based on the requested method type.
if request.method == "GET":
# functionality 1
elif request.method == "POST":
# functionality 2
elif request.method == "PUT":
# functionality 3
elif request.method == "DELETE":
# functionality 4
for request method GET data is passed along with url.
for request method POST data is passed inside body. In terms of security method type POST is better one.
book_id = Book.objects.get(id=id)
if request.method == 'POST':
book_save == BookForm(request.POST, request.FILES, instance=book_id)
if book_save.is_valid():
book_save.save()
else:
book_save = BookForm(instance=book_id)
y = {
'form':book_save,
}
return render(request, 'pages/update.html', y)

Django form with __init__ doesn't clean fields

I have a django form I'm attempting to add CAPTCHA support to. However, this requires me to pass request.session to the form. To accomplish that, I added this constructor to the form:
def __init__(self, request=None, *args, **kwargs):
super(RegistrationForm, self).__init__(*args, **kwargs)
self.request = request
I then instantiate the RegistrationForm by passing the request object to it. However, when submitting the form, it fails to clean any of the fields. It just fails validation and passes a blank field back to the template. Here is the registration code that fails:
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
...do registration...
else:
return render(request, 'template.htm', {'form': form})
No matter what I put in the fields, it never validates. In fact, it doesn't even look like it cleans the fields. I just get back a new blank form after hitting the register button, no errors, nothing.
Any ideas?
Based on the code you posted, it looks as though you are passing request.POST into the request parameter for your RegistrationForm. i.e. you are doing the equivalent of:
form = RegistrationForm(request=request.POST)
What you really want to do is this:
form = RegistrationForm(request=request, data=request.POST)
Try this and see if it works for you.

A better pattern for Django form logic?

The standard pattern for the view logic for Django forms is thus:
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render_to_response('contact.html', {
'form': form,
})
This is fine in simple cases but quite easily descends into a complex mass of nested IF statements if your application logic gets a bit more complex.
Can anyone share their own cleaner approaches that avoid nested IF's and logic that depends on fall-through cases?
I'd be particularly interested in answers that don't rely on additional 3rd party apps.
One of the included class based views is FormView (documentation). The two main methods you'd be concerned with are form_valid and form_invalid.
from django.views.generic import FormView
from myapp.forms import MyForm
class MyView(FormView):
template_name = 'edit_something.html'
form_class = MyForm
success_url = '/success/' # you should use `reverse`, but let's stay focused.
def form_valid(self, form):
"""
This is what's called when the form is valid.
"""
return super(MyView, self).form_valid(form)
def form_invalid(self, form):
"""
This is what's called when the form is invalid.
"""
return self.render_to_response(self.get_context_data(form=form))
Alternatively you can override post, get or put methods and handle the form according to each type of request.
This is shortest approach I found:
def contact(request):
# if it's POST request it'll have data else it'll be unbound
form = ContactForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
return render_to_response('contact.html', { 'form': form, })
of course if you don't like nested if you could try reversing logic:
def contact(request):
template = 'contact.html'
if request.method != 'POST': # GET return:
return render_to_response(template, {'form': ContactForm()})
form = ContactForm(request.POST)
if not form.is_valid(): # FAIL return:
return render_to_response(template, {'form': form})
# here logic if user posted form and it's clean:
return HttpResponseRedirect('/thanks/')
For complex scenarios, you should really consider overriding various methods of your form class which are involved in the validation/sanitizing process. The BaseForm class defines a _post_clean() method with no behavior which is particularly meant to be overridden. Overriding _clean() properly is also pretty straight forward, you could do that too if you wanted to do something before clean() is called.
Reading the source of django.forms will give you a much clearer insight on how the forms work and discover the right pattern for your needs.
Here is what i tried so far to make view funcs cleaner:
Separate view functions for GET / POST
Obviously is_valid logic in form as state in prev post.
Overriding model save() method to make if form.is_valid() part cleaner ( you can hide other related objects creates inside one save() )
Move common parts of view-funcs code into separeate function.
Also if your GET part is not CPU or database intense you can do it above if req == POST..
in other words do it always..
I for example often do: ctx['form'] = ContactForm() at the top.. and then again
ContactForm(req.POST) inside if req == POST
BUT
django 1.3 Now have class based view.. And this give one a big opportunity
to make view extendable.. to make mixins.. not to write the save over and over.
I personally want to give it a shot and will try write django stuff in a new style with classes.
The main source of complexity in these cases is handling GETs and POSTs in the same view function. Separate the logic for each method into its own view and things become clearer.
The only duplication will be rendering the form html, but that particular part is concise and meaningful for both cases (i.e. not boilerplate), so that's acceptable.

Alternative to django form processing boilerplate?

The suggested pattern for processing a form in a view seems overly complex and non-DRY to me:
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render_to_response('contact.html', {
'form': form,
})
That's a lot of conditionals, it repeats the ContactForm() construction, and the whole block is repeated everywhere a view needs to process a form. Isn't there a better way of doing it?
You can avoid the repetition, of course. Mostly, you need to pass in as arguments the class of form and template name to use, a callable to process the cleaned data when a valid form is submitted, and a destination for the redirect after such processing; plus, you need a little extra code to call the form class just once, to produce either a bound or unbound form, and deal with it properly. I.e.:
def process_any_form(request,
form_class, template_file_name,
process_data_callable, redirect_destination):
form = form_class(request.POST if request.method == 'POST' else None)
if form.is_bound and form.is_valid():
process_data_callable(form.cleaned_data)
return HttpResponseRedirect(redirect_destination)
return render_to_response(template_file_name, {'form': form})
You are right it could be better, here is a better alternative (but keep reading):
def contact(request):
form = ContactForm(request.POST or None) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
return render_to_response('contact.html', {
'form': form,
})
This snippet comes from a talk called Advanced Django Form Usage from DjangoCon11.
Note that this will process an empty form as valid (even before submission) if all the fields are optional and you don't use CSRF protection. So to eliminate that risk, you better use this one:
def contact(request):
form = ContactForm(request.POST or None) # A form bound to the POST data
if request.method == 'POST' and form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
return render_to_response('contact.html', {
'form': form,
})
The boilerplate way of processing forms mixes two concerns: presenting a form to edit and processing the results. You could break this into two methods, which would introduce some duplication in the form of identical render_to_response() calls. By the time you refactored that, you might end up with something that's less readable than the single-method form above.
When I look at the boilerplate method, I don't see duplication. The two uses of ContactForm() are distinctly different. The two conditionals seem to me to fairly cleanly show the state transitions involved in processing a form (present a blank form, accept submissions until one is valid, process-and-redirect).
Alex's generic handler beat me to it, but FWIW we tend toward a less-generic version of his suggestion:
def contact(request):
post_data = request.POST if request.method == 'POST' else None
form = ContactForm(post_data)
if request.method == 'POST':
# perform normal validation checking, etc
return render_to_response('contact.html', {
'form': form,
})
If post_data is None, then the form is instantiated as being unbounded. Otherwise, bound processing continues as normal. It avoids a duplicated construction of ContactForm, but I agree with Dave's answer that the duplicate construction doesn't bother me as being a duplicate precisely because the construction parameters are different.
I got so tired of this that i wrote my own generic views to handle it. In the process, I discovered that django already has underdocumented generic views for forms processing. They are fairly direct analogues of the documented generic views, but accept forms, and basically follow the same template you used in your example. Ultimately, I found them too inflexible and stupid for my use (I don't want a create_or_update view, I wan't to treat those two actions seperately.)
Edit: You didn't like Fragsworth's answer, which points to the same thing i'm talking about, I assume you wont' like mine either. Here's an example for how it works.
# in urls.py
urlpatterns += patterns("",
(u'^...$', 'django.views.generic.create_update.update', {
'form_class': ContactForm })
)
ContactForm must have a save() method, and thats where your form processing logic goes.
One could write a function that handles the conditionals for all forms. You could do this by passing in a function specific to that form after "is_valid", such as:
def FormHandler(request, CleaningFunction, redirecturl):
if request.method = 'POST':
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
CleaningFunction(form) # Process the data in form.cleaned_data
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return form
Then you would call FormHandler from your view. Note this isn't tested and may have errors.
You can bypass django's forms module and just do it the old fashion way, you get more flexibility without too much loss IMHO.
Last time I looked at django forms was quite a while ago, I don't know if things have changed, but for instance, it doesn't really allow you build an ajax-style form; at least not easily.
Django provides several generic views for creating, editing, and deleting objects. Perhaps you could try these.