aboutsummaryrefslogtreecommitdiffstats
path: root/djangorestframework/validators.py
diff options
context:
space:
mode:
Diffstat (limited to 'djangorestframework/validators.py')
-rw-r--r--djangorestframework/validators.py199
1 files changed, 0 insertions, 199 deletions
diff --git a/djangorestframework/validators.py b/djangorestframework/validators.py
deleted file mode 100644
index d96e8d9e..00000000
--- a/djangorestframework/validators.py
+++ /dev/null
@@ -1,199 +0,0 @@
-"""Mixin classes that provide a validate(content) function to validate and cleanup request content"""
-from django import forms
-from django.db import models
-from djangorestframework.response import ResponseException
-from djangorestframework.utils import as_tuple
-
-class ValidatorMixin(object):
- """Base class for all ValidatorMixin classes, which simply defines the interface they provide."""
-
- def validate(self, content):
- """Given some content as input return some cleaned, validated content.
- Raises a ResponseException with status code 400 (Bad Request) on failure.
-
- Must be overridden to be implemented."""
- raise NotImplementedError()
-
-
-class FormValidatorMixin(ValidatorMixin):
- """Validator Mixin that uses forms for validation.
- Extends the ValidatorMixin interface to also provide a get_bound_form() method.
- (Which may be used by some emitters.)"""
-
- """The form class that should be used for validation, or None to turn off form validation."""
- form = None
- bound_form_instance = None
-
- def validate(self, content):
- """Given some content as input return some cleaned, validated content.
- Raises a ResponseException 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.
-
- On failure the ResponseException content is a dict which may contain 'errors' and 'field-errors' keys.
- If the 'errors' key exists it is a list of strings of non-field errors.
- If the 'field-errors' key exists it is a dict of {field name as string: list of errors as strings}."""
- return self._validate(content)
-
- def _validate(self, content, allowed_extra_fields=()):
- """Wrapped by validate to hide the extra_fields option that the ModelValidatorMixin uses.
- extra_fields is a list of fields which are not defined by the form, but which we still
- expect to see on the input."""
- bound_form = self.get_bound_form(content)
-
- if bound_form is None:
- return content
-
- self.bound_form_instance = bound_form
-
- seen_fields_set = set(content.keys())
- form_fields_set = set(bound_form.fields.keys())
- allowed_extra_fields_set = set(allowed_extra_fields)
-
- # In addition to regular validation we also ensure no additional fields are being passed in...
- unknown_fields = seen_fields_set - (form_fields_set | allowed_extra_fields_set)
-
- # Check using both regular validation, and our stricter no additional fields rule
- if bound_form.is_valid() and not unknown_fields:
- # Validation succeeded...
- cleaned_data = bound_form.cleaned_data
-
- cleaned_data.update(bound_form.files)
-
- # Add in any extra fields to the cleaned content...
- for key in (allowed_extra_fields_set & seen_fields_set) - set(cleaned_data.keys()):
- cleaned_data[key] = content[key]
-
- return cleaned_data
-
- # Validation failed...
- detail = {}
-
- if not bound_form.errors and not unknown_fields:
- detail = {u'errors': [u'No content was supplied.']}
-
- else:
- # Add any non-field errors
- if bound_form.non_field_errors():
- detail[u'errors'] = bound_form.non_field_errors()
-
- # Add standard field errors
- field_errors = dict((key, map(unicode, val)) for (key, val) in bound_form.errors.iteritems() if not key.startswith('__'))
-
- # Add any unknown field errors
- for key in unknown_fields:
- field_errors[key] = [u'This field does not exist.']
-
- if field_errors:
- detail[u'field-errors'] = field_errors
-
- # Return HTTP 400 response (BAD REQUEST)
- raise ResponseException(400, detail)
-
-
- def get_bound_form(self, content=None):
- """Given some content return a Django form bound to that content.
- If form validation is turned off (form class attribute is None) then returns None."""
- if not self.form:
- return None
-
- if not content is None:
- if hasattr(content, 'FILES'):
- return self.form(content, content.FILES)
- return self.form(content)
- return self.form()
-
-
-class ModelFormValidatorMixin(FormValidatorMixin):
- """Validator Mixin that uses forms for validation and falls back to a model form if no form is set.
- Extends the ValidatorMixin interface to also provide a get_bound_form() method.
- (Which may be used by some emitters.)"""
-
- """The form class that should be used for validation, or None to use model form validation."""
- form = None
-
- """The model class from which the model form should be constructed if no form is set."""
- model = None
-
- """The list of fields we expect to receive as input. Fields in this list will may be received with
- raising non-existent field errors, even if they do not exist as fields on the ModelForm.
-
- Setting the fields class attribute causes the exclude_fields class attribute to be disregarded."""
- fields = None
-
- """The list of fields to exclude from the Model. This is only used if the fields class attribute is not set."""
- exclude_fields = ('id', 'pk')
-
-
- # TODO: test the different validation here to allow for get get_absolute_url to be supplied on input and not bork out
- # TODO: be really strict on fields - check they match in the handler methods. (this isn't a validator thing tho.)
- def validate(self, content):
- """Given some content as input return some cleaned, validated content.
- Raises a ResponseException with status code 400 (Bad Request) on failure.
-
- Validation is standard form or model form validation,
- with an additional constraint that no extra unknown fields may be supplied,
- and that all fields specified by the fields class attribute must be supplied,
- even if they are not validated by the form/model form.
-
- On failure the ResponseException content is a dict which may contain 'errors' and 'field-errors' keys.
- If the 'errors' key exists it is a list of strings of non-field errors.
- If the 'field-errors' key exists it is a dict of {field name as string: list of errors as strings}."""
- return self._validate(content, allowed_extra_fields=self._property_fields_set)
-
-
- def get_bound_form(self, content=None):
- """Given some content return a Django form bound to that content.
-
- If the form class attribute has been explicitly set then use that class to create a Form,
- otherwise if model is set use that class to create a ModelForm, otherwise return None."""
-
- if self.form:
- # Use explict Form
- return super(ModelFormValidatorMixin, self).get_bound_form(content)
-
- elif self.model:
- # Fall back to ModelForm which we create on the fly
- class OnTheFlyModelForm(forms.ModelForm):
- class Meta:
- model = self.model
- #fields = tuple(self._model_fields_set)
-
- # Instantiate the ModelForm as appropriate
- if content and isinstance(content, models.Model):
- # Bound to an existing model instance
- return OnTheFlyModelForm(instance=content)
- elif not content is None:
- if hasattr(content, 'FILES'):
- return OnTheFlyModelForm(content, content.FILES)
- return OnTheFlyModelForm(content)
- return OnTheFlyModelForm()
-
- # Both form and model not set? Okay bruv, whatevs...
- return None
-
-
- @property
- def _model_fields_set(self):
- """Return a set containing the names of validated fields on the model."""
- model_fields = set(field.name for field in self.model._meta.fields)
-
- if self.fields:
- return model_fields & set(as_tuple(self.fields))
-
- return model_fields - set(as_tuple(self.exclude_fields))
-
- @property
- def _property_fields_set(self):
- """Returns a set containing the names of validated properties on the model."""
- property_fields = set(attr for attr in dir(self.model) if
- isinstance(getattr(self.model, attr, None), property)
- and not attr.startswith('_'))
-
- if self.fields:
- return property_fields & set(as_tuple(self.fields))
-
- return property_fields - set(as_tuple(self.exclude_fields))
-
-
-