Reputation: 9595
I am having a hard time wrapping my head around what request.POST is doing as a argument in the following example:
def addauthorView(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
first_name = form.cleaned_data['firstname']
last_name = form.cleaned_data['lastname']
user_email = form.cleaned_data['email']
c = AuthorModel(firstname=first_name, lastname=last_name, email=user_email)
c.save()
return HttpResponseRedirect('thanks/')
else:
form = ContactForm(request.POST)
return render(request, 'addauthor.html', {'form': form})
So I know that this works, but for some reason I cannot understand the magic that is happening with form = ContactForm(request.POST)
. Why does the ContactForm need the request.POST argument? What is happening behind the scenes?
Extra question, why is form = ContactForm(request.POST)
then repeated in the else:
block. Why is that helpful and when is that useful? Examples?
Upvotes: 5
Views: 9879
Reputation: 1558
In a nutshell, request.POST
is simply the data that was sent when the form was submitted. It's a dictionary of what the user submitted for firstname
, lastname
and email
in your code sample. For those that come from a PHP background, it's what is provided in $_POST
.
form = ContactForm(request.POST)
binds the data to the form class so Django can do fun stuff like validate inputs with is_valid()
.
Why then, would you add request.POST
to the else:
block? Well, have you ever submitted a form to a website and when there was an error you had to completely fill out the form again? That's a crappy user experience, right? By sending the form back to the user with the data from request.POST
, you can re-render what the user inputed - along with helpful extras such as error messages - so they can fix them and resubmit.
EDIT: To expand, here is the init method from the BaseForm class in Django:
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=None,
empty_permitted=False):
self.is_bound = data is not None or files is not None
self.data = data or {}
self.files = files or {}
self.auto_id = auto_id
self.prefix = prefix
self.initial = initial or {}
self.error_class = error_class
# Translators: This is the default suffix added to form field labels
self.label_suffix = label_suffix if label_suffix is not None else _(':')
self.empty_permitted = empty_permitted
self._errors = None # Stores the errors after clean() has been called.
self._changed_data = None
# The base_fields class attribute is the *class-wide* definition of
# fields. Because a particular *instance* of the class might want to
# alter self.fields, we create self.fields here by copying base_fields.
# Instances should always modify self.fields; they should not modify
# self.base_fields.
self.fields = copy.deepcopy(self.base_fields)
When you pass request.POST
to your form class, you're really doing data=request.POST
. That in turn triggers the self.is_bound = True
Upvotes: 12