Использование методов класса MongoEngine Document для пользовательской проверки и предварительных сбережений

В настоящее время я изучаю возможности "компоновщика документов объекта MongoEngine". В настоящее время мне не ясно, насколько я могу перенести мою логику проверки и создания объекта в объекты Document.

У меня сложилось впечатление, что это не должно быть проблемой, но я не нахожу много примеров/предостережений/лучших практик в отношении проблем, таких как

  • Пользовательские функции проверки, которые автоматически вызывают функцию save() для оценки допустимости содержимого поля;
  • Автоматическая генерация идентификатора в файле save() на основе хэша содержимого поля;

Я думаю, мне нужно переопределить метод save(), чтобы я мог вызвать свою собственную логику, но отсутствие примеров заставляет меня поверить, что это может быть неправильный подход...

Любые примеры или ссылки на высококачественные кодовые базы с использованием mongoEngine приветствуются.

Ответы

Ответ 1

Вы можете переопределить 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)

Вы можете определить крючки для данного модельного класса довольно естественным образом:

class SomeModel(MyDocument):
    # fields...

    _pre_save_hooks = [
        some_callable,
        another_callable
    ]

Ответ 2

Пользовательская проверка теперь должна выполняться реализующей метод 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()

Изменить: Тем не менее, вы должны быть осторожны, используя clean(), так как он вызывается из validate() до проверки модели на основе правил, установленных в определении модели.

Ответ 3

Вы также можете переопределить метод проверки в документе, но вам нужно будет усвоить ошибки документа Суперкласса, чтобы вы могли добавить к ним свои ошибки.

Это, к сожалению, зависит от внутренних деталей реализации в 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)

Кроме того, теперь в MongoEngine имеется правильная поддержка сигналов для обработки других видов перехватов (например, генерация идентификатора, упомянутая в вопросе).

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