WTForms: passing form values back to the user on post
When both the GET and POST methods are in the same handler class, and I want to populate form fields with user input after failed form validation, I do this...
Class CommentHandler(BaseHandler): def get(self, form=None): if form is None: # create new form unless populated form is passed in form = CommentForm() # query DB and create template context self.render('page.html', **context) def post(self): form = CommentForm(self.request.POST) if form.validate(): # populate entity with form data and save to DB return self.redirect_to('page') self.get(form=form) # pass populated form back to user for editing
I don't know if this is the best way to get form data back to the user, but it seems to work. My question is: how do I pass that data back into the form if the GET and POST methods are in different handler classes?
class PageHandler(BaseHandler): def get(self): # displays form to user class CommentHandler(BaseHandler): def post(self): # processes POSTed form data... # but if form.validate() fails, # how can I pass the form data back to the user # so they can edit their form input?
When you post and call validate() WTForms binds the form encoded data to the Form instance. An http POST can return a response just like a GET this is why you sometimes get those funny messages in your browser when a server application has failed validation and you try to refresh. Its because the refresh action is going to invoke the GET processing pipeline and you will lose your POST data.
What you need to do instead of delegating back to the get implementation you just need to render a response from your post implementation that passes Form instance with the data bound to it back in the response. If you have set your template up in the recommended way the data will automatically show up in the appropriate fields. Below is a snippet of what your Handler might look like.
def post(self): form = CommentForm(self.request.POST) if form.validate(): # populate entity with form data and save to DB return self.redirect_to('page') # If we are here it means we failed validation # We need to send back the data the use supplied # with error messages so we can re-render the form # with their data and error messages indicating why # it was rejected. self.render('page.html', form=form) # pass populated form back to user for editing
This of course assumes that your page.html knows what to do with the Form instance.
Here's one workflow that may help to solve your problem. I chose to provide a workflow instead of a specific code snippet in order to avoid being too prescriptive in the technology you use to solve the problem.
GET if session contains form data: add form data from session to template context display form POST if form validates: clear this form data from session save to db else: save form data to session redirect to GET handler