Added clean method to documents for pre validation data cleaning (MongoEngine/mongoengine#60)
This commit is contained in:
@@ -15,7 +15,9 @@ from .common import get_document, ALLOW_INHERITANCE
|
||||
from .datastructures import BaseDict, BaseList
|
||||
from .fields import ComplexBaseField
|
||||
|
||||
__all__ = ('BaseDocument', )
|
||||
__all__ = ('BaseDocument', 'NON_FIELD_ERRORS')
|
||||
|
||||
NON_FIELD_ERRORS = '__all__'
|
||||
|
||||
|
||||
class BaseDocument(object):
|
||||
@@ -82,11 +84,6 @@ class BaseDocument(object):
|
||||
if hasattr(self, '_changed_fields'):
|
||||
self._mark_as_changed(name)
|
||||
|
||||
# Check if the user has created a new instance of a class
|
||||
if (self._is_document and self._initialised
|
||||
and self._created and name == self._meta['id_field']):
|
||||
super(BaseDocument, self).__setattr__('_created', False)
|
||||
|
||||
if (self._is_document and not self._created and
|
||||
name in self._meta.get('shard_key', tuple()) and
|
||||
self._data.get(name) != value):
|
||||
@@ -94,6 +91,11 @@ class BaseDocument(object):
|
||||
msg = "Shard Keys are immutable. Tried to update %s" % name
|
||||
raise OperationError(msg)
|
||||
|
||||
# Check if the user has created a new instance of a class
|
||||
if (self._is_document and self._initialised
|
||||
and self._created and name == self._meta['id_field']):
|
||||
super(BaseDocument, self).__setattr__('_created', False)
|
||||
|
||||
super(BaseDocument, self).__setattr__(name, value)
|
||||
|
||||
def __getstate__(self):
|
||||
@@ -171,6 +173,16 @@ class BaseDocument(object):
|
||||
else:
|
||||
return hash(self.pk)
|
||||
|
||||
def clean(self):
|
||||
"""
|
||||
Hook for doing document level data cleaning before validation is run.
|
||||
|
||||
Any ValidationError raised by this method will not be associated with
|
||||
a particular field; it will have a special-case association with the
|
||||
field defined by NON_FIELD_ERRORS.
|
||||
"""
|
||||
pass
|
||||
|
||||
def to_mongo(self):
|
||||
"""Return data dictionary ready for use with MongoDB.
|
||||
"""
|
||||
@@ -203,20 +215,33 @@ class BaseDocument(object):
|
||||
data[name] = field.to_mongo(self._data.get(name, None))
|
||||
return data
|
||||
|
||||
def validate(self):
|
||||
def validate(self, clean=True):
|
||||
"""Ensure that all fields' values are valid and that required fields
|
||||
are present.
|
||||
"""
|
||||
# Ensure that each field is matched to a valid value
|
||||
errors = {}
|
||||
if clean:
|
||||
try:
|
||||
self.clean()
|
||||
except ValidationError, error:
|
||||
errors[NON_FIELD_ERRORS] = error
|
||||
|
||||
# Get a list of tuples of field names and their current values
|
||||
fields = [(field, self._data.get(name))
|
||||
for name, field in self._fields.items()]
|
||||
|
||||
# Ensure that each field is matched to a valid value
|
||||
errors = {}
|
||||
EmbeddedDocumentField = _import_class("EmbeddedDocumentField")
|
||||
GenericEmbeddedDocumentField = _import_class("GenericEmbeddedDocumentField")
|
||||
|
||||
for field, value in fields:
|
||||
if value is not None:
|
||||
try:
|
||||
field._validate(value)
|
||||
if isinstance(field, (EmbeddedDocumentField,
|
||||
GenericEmbeddedDocumentField)):
|
||||
field._validate(value, clean=clean)
|
||||
else:
|
||||
field._validate(value)
|
||||
except ValidationError, error:
|
||||
errors[field.name] = error.errors or error
|
||||
except (ValueError, AttributeError, AssertionError), error:
|
||||
@@ -224,6 +249,7 @@ class BaseDocument(object):
|
||||
elif field.required and not getattr(field, '_auto_gen', False):
|
||||
errors[field.name] = ValidationError('Field is required',
|
||||
field_name=field.name)
|
||||
|
||||
if errors:
|
||||
raise ValidationError('ValidationError', errors=errors)
|
||||
|
||||
|
||||
@@ -105,12 +105,12 @@ class BaseField(object):
|
||||
"""
|
||||
return value
|
||||
|
||||
def validate(self, value):
|
||||
def validate(self, value, clean=True):
|
||||
"""Perform validation on a value.
|
||||
"""
|
||||
pass
|
||||
|
||||
def _validate(self, value):
|
||||
def _validate(self, value, **kwargs):
|
||||
Document = _import_class('Document')
|
||||
EmbeddedDocument = _import_class('EmbeddedDocument')
|
||||
# check choices
|
||||
@@ -138,7 +138,7 @@ class BaseField(object):
|
||||
raise ValueError('validation argument for "%s" must be a '
|
||||
'callable.' % self.name)
|
||||
|
||||
self.validate(value)
|
||||
self.validate(value, **kwargs)
|
||||
|
||||
|
||||
class ComplexBaseField(BaseField):
|
||||
|
||||
Reference in New Issue
Block a user