Merge pull request #2106 from bagerard/add_validation_to_doc
Add a documentation page for validation
This commit is contained in:
commit
9f82a02ddf
@ -426,19 +426,6 @@ either a single field name, or a list or tuple of field names::
|
||||
first_name = StringField()
|
||||
last_name = StringField(unique_with='first_name')
|
||||
|
||||
Skipping Document validation on save
|
||||
------------------------------------
|
||||
You can also skip the whole document validation process by setting
|
||||
``validate=False`` when calling the :meth:`~mongoengine.document.Document.save`
|
||||
method::
|
||||
|
||||
class Recipient(Document):
|
||||
name = StringField()
|
||||
email = EmailField()
|
||||
|
||||
recipient = Recipient(name='admin', email='root@localhost')
|
||||
recipient.save() # will raise a ValidationError while
|
||||
recipient.save(validate=False) # won't
|
||||
|
||||
Document collections
|
||||
====================
|
||||
|
@ -41,35 +41,6 @@ already exist, then any changes will be updated atomically. For example::
|
||||
.. seealso::
|
||||
:ref:`guide-atomic-updates`
|
||||
|
||||
Pre save data validation and cleaning
|
||||
-------------------------------------
|
||||
MongoEngine allows you to create custom cleaning rules for your documents when
|
||||
calling :meth:`~mongoengine.Document.save`. By providing a custom
|
||||
:meth:`~mongoengine.Document.clean` method you can do any pre validation / data
|
||||
cleaning.
|
||||
|
||||
This might be useful if you want to ensure a default value based on other
|
||||
document values for example::
|
||||
|
||||
class Essay(Document):
|
||||
status = StringField(choices=('Published', 'Draft'), required=True)
|
||||
pub_date = DateTimeField()
|
||||
|
||||
def clean(self):
|
||||
"""Ensures that only published essays have a `pub_date` and
|
||||
automatically sets `pub_date` if essay is published and `pub_date`
|
||||
is not set"""
|
||||
if self.status == 'Draft' and self.pub_date is not None:
|
||||
msg = 'Draft entries should not have a publication date.'
|
||||
raise ValidationError(msg)
|
||||
# Set the pub_date for published items if not set.
|
||||
if self.status == 'Published' and self.pub_date is None:
|
||||
self.pub_date = datetime.now()
|
||||
|
||||
.. note::
|
||||
Cleaning is only called if validation is turned on and when calling
|
||||
:meth:`~mongoengine.Document.save`.
|
||||
|
||||
Cascading Saves
|
||||
---------------
|
||||
If your document contains :class:`~mongoengine.fields.ReferenceField` or
|
||||
|
@ -10,6 +10,7 @@ User Guide
|
||||
defining-documents
|
||||
document-instances
|
||||
querying
|
||||
validation
|
||||
gridfs
|
||||
signals
|
||||
text-indexes
|
||||
|
123
docs/guide/validation.rst
Normal file
123
docs/guide/validation.rst
Normal file
@ -0,0 +1,123 @@
|
||||
====================
|
||||
Document Validation
|
||||
====================
|
||||
|
||||
By design, MongoEngine strictly validates the documents right before they are inserted in MongoDB
|
||||
and makes sure they are consistent with the fields defined in your models.
|
||||
|
||||
MongoEngine makes the assumption that the documents that exists in the DB are compliant with the schema.
|
||||
This means that Mongoengine will not validate a document when an object is loaded from the DB into an instance
|
||||
of your model but this operation may fail under some circumstances (e.g. if there is a field in
|
||||
the document fetched from the database that is not defined in your model).
|
||||
|
||||
|
||||
Built-in validation
|
||||
===================
|
||||
|
||||
Mongoengine provides different fields that encapsulate the corresponding validation
|
||||
out of the box. Validation runs when calling `.validate()` or `.save()`
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from mongoengine import Document, EmailField
|
||||
|
||||
class User(Document):
|
||||
email = EmailField()
|
||||
age = IntField(min_value=0, max_value=99)
|
||||
|
||||
user = User(email='invalid@', age=24)
|
||||
user.validate() # raises ValidationError (Invalid email address: ['email'])
|
||||
user.save() # raises ValidationError (Invalid email address: ['email'])
|
||||
|
||||
user2 = User(email='john.doe@garbage.com', age=1000)
|
||||
user2.save() # raises ValidationError (Integer value is too large: ['age'])
|
||||
|
||||
Custom validation
|
||||
=================
|
||||
|
||||
The following feature can be used to customize the validation:
|
||||
|
||||
* Field `validation` parameter
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def not_john_doe(name):
|
||||
if name == 'John Doe':
|
||||
raise ValidationError("John Doe is not a valid name")
|
||||
|
||||
class Person(Document):
|
||||
full_name = StringField(validation=not_john_doe)
|
||||
|
||||
Person(full_name='Billy Doe').save()
|
||||
Person(full_name='John Doe').save() # raises ValidationError (John Doe is not a valid name)
|
||||
|
||||
|
||||
* Document `clean` method
|
||||
|
||||
This method is called as part of :meth:`~mongoengine.document.Document.save` and should be used to provide
|
||||
custom model validation and/or to modify some of the field values prior to validation.
|
||||
For instance, you could use it to automatically provide a value for a field, or to do validation
|
||||
that requires access to more than a single field.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Essay(Document):
|
||||
status = StringField(choices=('Published', 'Draft'), required=True)
|
||||
pub_date = DateTimeField()
|
||||
|
||||
def clean(self):
|
||||
# Validate that only published essays have a `pub_date`
|
||||
if self.status == 'Draft' and self.pub_date is not None:
|
||||
raise ValidationError('Draft entries should not have a publication date.')
|
||||
# Set the pub_date for published items if not set.
|
||||
if self.status == 'Published' and self.pub_date is None:
|
||||
self.pub_date = datetime.now()
|
||||
|
||||
.. note::
|
||||
Cleaning is only called if validation is turned on and when calling
|
||||
:meth:`~mongoengine.Document.save`.
|
||||
|
||||
* Adding custom Field classes
|
||||
|
||||
We recommend as much as possible to use fields provided by MongoEngine. However, it is also possible
|
||||
to subclass a Field and encapsulate some validation by overriding the `validate` method
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AgeField(IntField):
|
||||
|
||||
def validate(self, value):
|
||||
super(AgeField, self).validate(value) # let IntField.validate run first
|
||||
if value == 60:
|
||||
self.error('60 is not allowed')
|
||||
|
||||
class Person(Document):
|
||||
age = AgeField(min_value=0, max_value=99)
|
||||
|
||||
Person(age=20).save() # passes
|
||||
Person(age=1000).save() # raises ValidationError (Integer value is too large: ['age'])
|
||||
Person(age=60).save() # raises ValidationError (Person:None) (60 is not allowed: ['age'])
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
When overriding `validate`, use `self.error("your-custom-error")` instead of raising ValidationError explicitly,
|
||||
it will provide a better context with the error message
|
||||
|
||||
Skipping validation
|
||||
====================
|
||||
|
||||
Although discouraged as it allows to violate fields constraints, if for some reason you need to disable
|
||||
the validation and cleaning of a document when you call :meth:`~mongoengine.document.Document.save`, you can use `.save(validate=False)`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Person(Document):
|
||||
age = IntField(max_value=100)
|
||||
|
||||
Person(age=1000).save() # raises ValidationError (Integer value is too large)
|
||||
|
||||
Person(age=1000).save(validate=False)
|
||||
person = Person.objects.first()
|
||||
assert person.age == 1000
|
||||
|
@ -215,7 +215,7 @@ class EmbeddedDocumentList(BaseList):
|
||||
Filters the list by only including embedded documents with the
|
||||
given keyword arguments.
|
||||
|
||||
This method only supports simple comparison (e.g: .filter(name='John Doe'))
|
||||
This method only supports simple comparison (e.g. .filter(name='John Doe'))
|
||||
and does not support operators like __gte, __lte, __icontains like queryset.filter does
|
||||
|
||||
:param kwargs: The keyword arguments corresponding to the fields to
|
||||
|
@ -314,7 +314,8 @@ class BaseDocument:
|
||||
|
||||
def clean(self):
|
||||
"""
|
||||
Hook for doing document level data cleaning before validation is run.
|
||||
Hook for doing document level data cleaning (usually validation or assignment)
|
||||
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
|
||||
|
@ -433,7 +433,7 @@ class DecimalField(BaseField):
|
||||
:param max_value: Validation rule for the maximum acceptable value.
|
||||
:param force_string: Store the value as a string (instead of a float).
|
||||
Be aware that this affects query sorting and operation like lte, gte (as string comparison is applied)
|
||||
and some query operator won't work (e.g: inc, dec)
|
||||
and some query operator won't work (e.g. inc, dec)
|
||||
:param precision: Number of decimal places to store.
|
||||
:param rounding: The rounding rule from the python decimal library:
|
||||
|
||||
|
@ -50,7 +50,7 @@ def _decorated_with_ver_requirement(func, mongo_version_req, oper):
|
||||
ran against MongoDB < v3.6.
|
||||
|
||||
:param mongo_version_req: The mongodb version requirement (tuple(int, int))
|
||||
:param oper: The operator to apply (e.g: operator.ge)
|
||||
:param oper: The operator to apply (e.g. operator.ge)
|
||||
"""
|
||||
|
||||
def _inner(*args, **kwargs):
|
||||
|
Loading…
x
Reference in New Issue
Block a user