使用MongoEngine Document类方法进行自定义验证和预保存挂钩

mhe*_*ans 14 python validation mongodb mongoengine

我目前正在探索MongoEngine"对象文档映射器"的可能性.目前我不清楚的是,我可以在多大程度上将验证和对象创建逻辑移动到Document对象本身.

我的印象是它应该不是问题,但我没有找到很多关于问题的例子/警告/最佳实践

  • 自定义验证函数,在save()上自动调用,以评估字段内容是否有效;
  • 根据字段内容的哈希值在save()上自动生成标识符;

我想我需要覆盖save()方法,以便我可以调用我的自定义逻辑,但是缺少示例会让我相信这可能是一种错误的方法......

任何示例或对使用mongoEngine的高质量代码库的引用都是受欢迎的.

Pry*_*die 23

现在应该通过在模型上实现clean()方法来完成自定义验证.

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()
Run Code Online (Sandbox Code Playgroud)

编辑:也就是说,您必须小心使用,clean()因为validate()在根据模型定义中设置的规则验证模型之前调用它.

  • 在我看来最好的方式.另请参阅MongoEngine源代码中的`clean()`函数中的注释:https://github.com/MongoEngine/mongoengine/blob/master/mongoengine/base/document.py#L230 - `Hook for doing document level运行验证前的数据清理.此方法引发的任何ValidationError都不会与特定字段关联; 它将与NON_FIELD_ERRORS定义的字段具有特殊情况关联.因此,如果您想要字段级验证,我认为您应该编写自定义字段. (2认同)

dcr*_*sta 14

您可以save()使用通常的警告来覆盖,您必须调用父类的方法.

如果您发现要为所有模型添加验证挂钩,则可以考虑创建类似以下内容的自定义子类Document:

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)
Run Code Online (Sandbox Code Playgroud)

然后,您可以以相当自然的方式为给定的模型类定义钩子:

class SomeModel(MyDocument):
    # fields...

    _pre_save_hooks = [
        some_callable,
        another_callable
    ]
Run Code Online (Sandbox Code Playgroud)


alv*_*vin 7

您还可以覆盖Document上的validate方法,但是您需要吞下超类Document错误,以便将错误添加到它们

遗憾的是,它依赖于MongoEngine中的内部实现细节,所以谁知道它将来是否会破坏.

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)
Run Code Online (Sandbox Code Playgroud)

此外,MongoEngine现在有适当的信号支持来处理其他类型的钩子(例如你在问题中提到的标识符生成).

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