-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2106 from bagerard/add_validation_to_doc
Add a documentation page for validation
- Loading branch information
Showing
8 changed files
with
129 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ User Guide | |
defining-documents | ||
document-instances | ||
querying | ||
validation | ||
gridfs | ||
signals | ||
text-indexes | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters