aboutsummaryrefslogtreecommitdiffstats
path: root/djangorestframework/validators.py
diff options
context:
space:
mode:
Diffstat (limited to 'djangorestframework/validators.py')
-rw-r--r--djangorestframework/validators.py91
1 files changed, 56 insertions, 35 deletions
diff --git a/djangorestframework/validators.py b/djangorestframework/validators.py
index d96e8d9e..609e6d36 100644
--- a/djangorestframework/validators.py
+++ b/djangorestframework/validators.py
@@ -4,25 +4,31 @@ 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."""
+
+class BaseValidator(object):
+ """Base class for all Validator classes, which simply defines the interface they provide."""
+
+ def __init__(self, view):
+ self.view = view
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.
-
+ Typically 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.)"""
+class FormValidator(BaseValidator):
+ """Validator class that uses forms for validation.
+ Also provides a get_bound_form() method which may be used by some renderers.
- """The form class that should be used for validation, or None to turn off form validation."""
- form = None
- bound_form_instance = None
+ The view class should provide `.form` attribute which specifies the form classmethod
+ to be used for validation.
+
+ On calling validate() this validator may set a `.bound_form_instance` attribute on the
+ view, which may be used by some renderers."""
+
def validate(self, content):
"""Given some content as input return some cleaned, validated content.
@@ -44,7 +50,7 @@ class FormValidatorMixin(ValidatorMixin):
if bound_form is None:
return content
- self.bound_form_instance = bound_form
+ self.view.bound_form_instance = bound_form
seen_fields_set = set(content.keys())
form_fields_set = set(bound_form.fields.keys())
@@ -78,7 +84,10 @@ class FormValidatorMixin(ValidatorMixin):
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('__'))
+ 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:
@@ -94,20 +103,21 @@ class FormValidatorMixin(ValidatorMixin):
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:
+ form_cls = getattr(self.view, 'form', None)
+
+ if not form_cls:
return None
- if not content is None:
+ if content is not None:
if hasattr(content, 'FILES'):
- return self.form(content, content.FILES)
- return self.form(content)
- return self.form()
+ return form_cls(content, content.FILES)
+ return form_cls(content)
+ return form_cls()
-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.)"""
+class ModelFormValidator(FormValidator):
+ """Validator class that uses forms for validation and otherwise falls back to a model form if no form is set.
+ Also provides a get_bound_form() method which may be used by some renderers."""
"""The form class that should be used for validation, or None to use model form validation."""
form = None
@@ -148,15 +158,18 @@ class ModelFormValidatorMixin(FormValidatorMixin):
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:
+ form_cls = getattr(self.view, 'form', None)
+ model_cls = getattr(self.view, 'model', None)
+
+ if form_cls:
# Use explict Form
- return super(ModelFormValidatorMixin, self).get_bound_form(content)
+ return super(ModelFormValidator, self).get_bound_form(content)
- elif self.model:
+ elif model_cls:
# Fall back to ModelForm which we create on the fly
class OnTheFlyModelForm(forms.ModelForm):
class Meta:
- model = self.model
+ model = model_cls
#fields = tuple(self._model_fields_set)
# Instantiate the ModelForm as appropriate
@@ -176,24 +189,32 @@ class ModelFormValidatorMixin(FormValidatorMixin):
@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)
+ model = getattr(self.view, 'model', None)
+ fields = getattr(self.view, 'fields', self.fields)
+ exclude_fields = getattr(self.view, 'exclude_fields', self.exclude_fields)
+
+ model_fields = set(field.name for field in model._meta.fields)
- if self.fields:
- return model_fields & set(as_tuple(self.fields))
+ if fields:
+ return model_fields & set(as_tuple(fields))
- return model_fields - set(as_tuple(self.exclude_fields))
+ return model_fields - set(as_tuple(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)
+ model = getattr(self.view, 'model', None)
+ fields = getattr(self.view, 'fields', self.fields)
+ exclude_fields = getattr(self.view, 'exclude_fields', self.exclude_fields)
+
+ property_fields = set(attr for attr in dir(model) if
+ isinstance(getattr(model, attr, None), property)
and not attr.startswith('_'))
- if self.fields:
- return property_fields & set(as_tuple(self.fields))
+ if fields:
+ return property_fields & set(as_tuple(fields))
- return property_fields - set(as_tuple(self.exclude_fields))
+ return property_fields - set(as_tuple(exclude_fields))