Merge pull request #130 from flashingpumpkin/master

Added an additional attribute `unknown_form_fields` to `FormResource`
This commit is contained in:
Tom Christie 2012-01-19 10:55:31 -08:00
commit a8ed7f9189
2 changed files with 24 additions and 3 deletions

View File

@ -78,13 +78,22 @@ class FormResource(Resource):
This can be overridden by a :attr:`form` attribute on the :class:`views.View`. This can be overridden by a :attr:`form` attribute on the :class:`views.View`.
""" """
allow_unknown_form_fields = False
"""
Flag to check for unknown fields when validating a form. If set to false and
we receive request data that is not expected by the form it raises an
:exc:`response.ErrorResponse` with status code 400. If set to true, only
expected fields are validated.
"""
def validate_request(self, data, files=None): def validate_request(self, data, files=None):
""" """
Given some content as input return some cleaned, validated content. Given some content as input return some cleaned, validated content.
Raises a :exc:`response.ErrorResponse` with status code 400 (Bad Request) on failure. Raises a :exc:`response.ErrorResponse` with status code 400 (Bad Request) on failure.
Validation is standard form validation, with an additional constraint that *no extra unknown fields* may be supplied. Validation is standard form validation, with an additional constraint that *no extra unknown fields* may be supplied
if :attr:`self.allow_unknown_form_fields` is ``False``.
On failure the :exc:`response.ErrorResponse` content is a dict which may contain :obj:`'errors'` and :obj:`'field-errors'` keys. On failure the :exc:`response.ErrorResponse` content is a dict which may contain :obj:`'errors'` and :obj:`'field-errors'` keys.
If the :obj:`'errors'` key exists it is a list of strings of non-field errors. If the :obj:`'errors'` key exists it is a list of strings of non-field errors.
@ -132,7 +141,7 @@ class FormResource(Resource):
unknown_fields = unknown_fields - set(('csrfmiddlewaretoken', '_accept', '_method')) # TODO: Ugh. unknown_fields = unknown_fields - set(('csrfmiddlewaretoken', '_accept', '_method')) # TODO: Ugh.
# Check using both regular validation, and our stricter no additional fields rule # Check using both regular validation, and our stricter no additional fields rule
if bound_form.is_valid() and not unknown_fields: if bound_form.is_valid() and (self.allow_unknown_form_fields or not unknown_fields):
# Validation succeeded... # Validation succeeded...
cleaned_data = bound_form.cleaned_data cleaned_data = bound_form.cleaned_data
@ -389,7 +398,7 @@ class ModelResource(FormResource):
""" """
model_fields = set(field.name for field in self.model._meta.fields) model_fields = set(field.name for field in self.model._meta.fields)
if fields: if self.fields:
return model_fields & set(as_tuple(self.fields)) return model_fields & set(as_tuple(self.fields))
return model_fields - set(as_tuple(self.exclude)) return model_fields - set(as_tuple(self.exclude))

View File

@ -138,6 +138,14 @@ class TestFormValidation(TestCase):
content = {'qwerty': 'uiop', 'extra': 'extra'} content = {'qwerty': 'uiop', 'extra': 'extra'}
validator._validate(content, None, allowed_extra_fields=('extra',)) validator._validate(content, None, allowed_extra_fields=('extra',))
def validation_allows_unknown_fields_if_explicitly_allowed(self, validator):
"""If we set ``unknown_form_fields`` on the form resource, then don't
raise errors on unexpected request data"""
content = {'qwerty': 'uiop', 'extra': 'extra'}
validator.allow_unknown_form_fields = True
self.assertDictEqual({'qwerty': u'uiop'}, validator.validate_request(content, None), "Resource didn't accept unknown fields.")
validator.allow_unknown_form_fields = False
def validation_does_not_require_extra_fields_if_explicitly_set(self, validator): def validation_does_not_require_extra_fields_if_explicitly_set(self, validator):
"""If we include an allowed_extra_fields paramater on _validate, then do not fail if we do not have fields with those names.""" """If we include an allowed_extra_fields paramater on _validate, then do not fail if we do not have fields with those names."""
content = {'qwerty': 'uiop'} content = {'qwerty': 'uiop'}
@ -201,6 +209,10 @@ class TestFormValidation(TestCase):
def test_validation_allows_extra_fields_if_explicitly_set(self): def test_validation_allows_extra_fields_if_explicitly_set(self):
validator = self.MockFormResource(self.MockFormView()) validator = self.MockFormResource(self.MockFormView())
self.validation_allows_extra_fields_if_explicitly_set(validator) self.validation_allows_extra_fields_if_explicitly_set(validator)
def test_validation_allows_unknown_fields_if_explicitly_allowed(self):
validator = self.MockFormResource(self.MockFormView())
self.validation_allows_unknown_fields_if_explicitly_allowed(validator)
def test_validation_does_not_require_extra_fields_if_explicitly_set(self): def test_validation_does_not_require_extra_fields_if_explicitly_set(self):
validator = self.MockFormResource(self.MockFormView()) validator = self.MockFormResource(self.MockFormView())