Using MongoEngine Document class methods for custom validation and pre-save hooks

自作多情 提交于 2019-12-03 07:20:28

问题


I am currently exploring the possibilities of the MongoEngine "object document mapper". What is currently not clear to me is to what extent I can move my validation and object creation logic to the Document objects themselves.

I have the impression that it should not be a problem, but I'm not finding a lot of examples/caveats/best practices regarding issues as

  • Custom validation functions that are automatically called on save() to evaluate if field contents are valid;
  • Automatic generation of the identifier on save(), based on the hash of the contents of a field;

I think I need to override the save() method, so that I can call my custom logic, but the lack of examples leads me to believe that that may be a wrong approach...

Any examples, or references to high-quality codebases using mongoEngine, are welcome.


回答1:


You can override save(), with the usual caveat that you must call the parent class's method.

If you find that you want to add validation hooks to all your models, you might consider creating a custom child class of Document something like:

class MyDocument(mongoengine.Document):

    def save(self, *args, **kwargs):
        for hook in self._pre_save_hooks:
            # the callable can raise an exception if
            # it determines that it is inappropriate
            # to save this instance; or it can modify
            # the instance before it is saved
            hook(self):

        super(MyDocument, self).save(*args, **kwargs)

You can then define hooks for a given model class in a fairly natural way:

class SomeModel(MyDocument):
    # fields...

    _pre_save_hooks = [
        some_callable,
        another_callable
    ]



回答2:


Custom validation should now be done by implementing the clean() method on a model.

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 the pub_date if published and 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()

Edit: That said, you have to be careful using clean() as it is called from validate() prior to validating the model based on the the rules set in your model definition.




回答3:


You could also override the validate method on Document, but you'd need to swallow the superclass Document errors so you can add your errors to them

This unfortunately relies on the internal implementation details in MongoEngine, so who knows if it will break in the future.

class MyDoc(Document):
    def validate(self):
        errors = {}
        try:
            super(MyDoc, self).validate()
        except ValidationError as e:
            errors = e.errors

        # Your custom validation here...
        # Unfortunately this might swallow any other errors on 'myfield'
        if self.something_is_wrong():
            errors['myfield'] = ValidationError("this field is wrong!", field_name='myfield')

        if errors:
            raise ValidationError('ValidationError', errors=errors)

Also, there is proper signal support now in MongoEngine for handling other kinds of hooks (such as the identifier generation you mentioned in the question).

http://mongoengine.readthedocs.io/en/latest/guide/signals.html



来源:https://stackoverflow.com/questions/6102103/using-mongoengine-document-class-methods-for-custom-validation-and-pre-save-hook

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!