How could it be easier to integration custom field validation with current field validation ?
Implementing it with keyword validation on Field does not enable to customize ValidationError object.
Are there good practices about it with the current V of mongoengine ?
Cheers,
EDIT:
I ended up subclassing mongoengine fields and overwriting the validate methods by first calling the parents validate within the redefinition.
Would be happy to have a shared experience on this though,
hey @BenCoDev , can you share your strategy for this kind of case?
Here is my implementation example:
class MyDoc(Document):
def name_validation(name):
assert name.startswith("a"), "name does not start with 'a'"
name = StringField(max_length=255, required=True)
name.validate = name_validation
mydoc = MyDoc(name="123")
I would like to know yours :)
@JWDobken it's a bit dangerous to implement the validate method like that.
You're overriding the StringField validate method completely and name_validation is not calling the StringField.validate method with super. This means that you can add a name bigger than 255 characters because you completely ignored that check. If you want to try it for yourself go ahead and do mydoc = MyDoc(name="a"*300) it runs and saves when it shouldn't.
I found the clean method approach enough for my use case. Your example would look like this and now it also won't allow for names bigger than 255 characters and it should. I know this is not a specific field check but you can still encapsulate the checking of each field in a method and put them all on the clean method.
from mongoengine import Document, StringField, ValidationError
class MyDoc(Document):
name = StringField(min_length=3, max_length=255, required=True)
@staticmethod
def name_validation(name):
if not name.startswith("a"):
raise ValidationError("name does not start with 'a'")
def clean(self):
self.name_validation(self.name)
mydoc = MyDoc(name="aaa"*256)
# will throw ValidationError: ValidationError (MyDoc:None)
# (String value is too long: ['name'])
mydoc.save()
# ValidationError: ValidationError (MyDoc:None)
# (name does not start with 'a': ['__all__'])
mydoc = MyDoc(name="aaa"*256).save()
I tried making it work with super but I wasn't sure how to access StringField validate, the closest I got was this but it isn't working, and I'm not willing to keep trying to make it work as the clean method works for me now.
I hope this helps as I was also a bit lost when trying to find a good way to do my custom checks before saving a document. If there's a better way or someone can explain how to properly override a Field validate method please do it.
The feature isn't well know nor documented (to be fixed) and the online doc isn't up to date (due to a bug) but any fields can take a validation parameter which is a callable
E.g:
def _not_empty(z):
if not z:
raise ValidationError('cantbeempty')
class Person(Document):
name = StringField(validation=_not_empty)
Note that:
Thanks for that merge request, it will be very helpful. I didn't try the validation arg because I didn't get how it was supposed to be used, also reading this "Generally this is deprecated in favor of the FIELD.validate method" confused me and led me to find another option like clean.
Most helpful comment
@JWDobken it's a bit dangerous to implement the validate method like that.
You're overriding the
StringFieldvalidate method completely andname_validationis not calling theStringField.validatemethod with super. This means that you can add a name bigger than 255 characters because you completely ignored that check. If you want to try it for yourself go ahead and domydoc = MyDoc(name="a"*300)it runs and saves when it shouldn't.I found the clean method approach enough for my use case. Your example would look like this and now it also won't allow for names bigger than 255 characters and it should. I know this is not a specific field check but you can still encapsulate the checking of each field in a method and put them all on the clean method.
I tried making it work with super but I wasn't sure how to access StringField validate, the closest I got was this but it isn't working, and I'm not willing to keep trying to make it work as the clean method works for me now.
I hope this helps as I was also a bit lost when trying to find a good way to do my custom checks before saving a document. If there's a better way or someone can explain how to properly override a Field validate method please do it.