Skip to content

Instantly share code, notes, and snippets.

@danjac
Created January 17, 2014 17:46
Show Gist options
  • Save danjac/8477954 to your computer and use it in GitHub Desktop.
Save danjac/8477954 to your computer and use it in GitHub Desktop.
Integration of wtforms 2 and Pyramid, including CSRF stuff.
from webob.multidict import MultiDict
from wtforms import Form as BaseForm
from wtforms.csrf.core import CSRF as BaseCSRF
class Form(BaseForm):
def __init__(self, request, formdata=None, *args, **kwargs):
self.request = request
formdata = formdata or self.request.POST
# we need an '_obj' for handling unique validators etc
self._obj = kwargs.pop('obj', None)
super(Form, self).__init__(formdata, obj=self._obj, *args, **kwargs)
def __json__(self, request):
return {'errors': self.errors, 'data': self.data}
@classmethod
def from_json(cls, request, *args, **kwargs):
"""Parses from JSON body in request, handy for Angular etc"""
return cls(request, MultiDict(request.json_body), *args, **kwargs)
def handle(self):
"""
Handles full form life-cycle. Checks if request method PUT/POST,
runs validate, if invalid sets response status to 400 (Bad Request).
Typical usage:
@view_config(route_name='submit', renderer='submit.mako')
def submit(request):
form = MyForm(request)
if form.handle():
# do whatever
return HTTPSeeOther(...)
return {'form': form}
"""
if self.request.method not in ('POST', 'PUT'):
return False
if self.validate():
return True
# 400 Bad request
self.request.response.status_int = 400
return False
# template helper methods
@property
def is_multipart(self):
for field in self:
if field.type == 'FileField':
return True
return False
@property
def hidden_fields(self):
return [field for field in self
if getattr(field.widget, 'input_type', None) == 'hidden']
@property
def submit_fields(self):
return [field for field in self if field.type == 'SubmitField']
@property
def editable_fields(self):
non_editable_fields = self.hidden_fields + self.submit_fields
return [field for field in self if field not in non_editable_fields]
class CSRF(BaseCSRF):
def setup_form(self, form):
self.request = form.request
return super(CSRF, self).setup_form(form)
def generate_csrf_token(self, csrf_context):
return self.request.session.get_csrf_token()
class SecureMeta(object):
csrf = True
csrf_class = CSRF
class SecureForm(Form):
"""Hooks in CSRF meta by default"""
class Meta(SecureMeta):
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment