rework validation documentation based on review

This commit is contained in:
Bastien Gérard 2020-10-18 21:11:16 +02:00
parent c218c8bb6c
commit 3fca3739de
4 changed files with 30 additions and 64 deletions

View File

@ -426,19 +426,6 @@ either a single field name, or a list or tuple of field names::
first_name = StringField() first_name = StringField()
last_name = StringField(unique_with='first_name') 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 Document collections
==================== ====================

View File

@ -41,35 +41,6 @@ already exist, then any changes will be updated atomically. For example::
.. seealso:: .. seealso::
:ref:`guide-atomic-updates` :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 Cascading Saves
--------------- ---------------
If your document contains :class:`~mongoengine.fields.ReferenceField` or If your document contains :class:`~mongoengine.fields.ReferenceField` or

View File

@ -3,10 +3,11 @@ Document Validation
==================== ====================
By design, MongoEngine strictly validates the documents right before they are inserted in MongoDB By design, MongoEngine strictly validates the documents right before they are inserted in MongoDB
and make sure they are consistent with the fields defined in your models. and makes sure they are consistent with the fields defined in your models.
Mongoengine will not validate a document when an object is loaded from the DB into an instance MongoEngine makes the assumption that the documents that exists in the DB are compliant with the schema.
of your model but this operation will fail under some circumstances (e.g. if there is a field in 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). the document fetched from the database that is not defined in your model).
@ -53,23 +54,28 @@ The following feature can be used to customize the validation:
* Document `clean` method * Document `clean` method
Although not its primary use case, `clean` may be use to do validation that involves multiple fields. This method is called as part of :meth:`~mongoengine.document.Document.save` and should be used to provide
Note that `clean` runs before the validation when you save a Document. 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 .. code-block:: python
class Person(Document): class Essay(Document):
first_name = StringField() status = StringField(choices=('Published', 'Draft'), required=True)
last_name = StringField() pub_date = DateTimeField()
def clean(self): def clean(self):
if self.first_name == 'John' and self.last_name == 'Doe': # Validate that only published essays have a `pub_date`
raise ValidationError('John Doe is not a valid name') if self.status == 'Draft' and self.pub_date is not None:
raise ValidationError('Draft entries should not have a publication date.')
Person(first_name='Billy', last_name='Doe').save() # Set the pub_date for published items if not set.
Person(first_name='John', last_name='Doe').save() # raises ValidationError (John Doe is not a valid name) 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 * Adding custom Field classes
@ -98,19 +104,20 @@ to subclass a Field and encapsulate some validation by overriding the `validate`
When overriding `validate`, use `self.error("your-custom-error")` instead of raising ValidationError explicitly, When overriding `validate`, use `self.error("your-custom-error")` instead of raising ValidationError explicitly,
it will provide a better context with the error message it will provide a better context with the error message
Disabling validation Skipping validation
==================== ====================
We do not recommend to do this but if for some reason you need to disable the validation of a document Although discouraged as it allows to violate fields constraints, if for some reason you need to disable
when you call `.save()`, you can use `.save(validate=False)`. the validation and cleaning of a document when you call `.save()`, you can use `.save(validate=False)`.
.. code-block:: python .. code-block:: python
class Person(Document): class Person(Document):
age = IntField() age = IntField(max_value=100)
Person(age='garbage').save() # raises ValidationError (garbage could not be converted to int: ['age']) Person(age=1000).save() # raises ValidationError (Integer value is too large)
Person(age='garbage').save(validate=False) Person(age=1000).save(validate=False)
person = Person.objects.first() person = Person.objects.first()
assert person.age == 'garbage' assert person.age == 1000

View File

@ -314,7 +314,8 @@ class BaseDocument:
def clean(self): 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 Any ValidationError raised by this method will not be associated with
a particular field; it will have a special-case association with the a particular field; it will have a special-case association with the