Подтвердить что ты не робот

Метод clean() в модели и проверка поля

У меня проблема с методом модели clean() и базовой проверкой поля. здесь моя модель и метод clean().

class Trial(models.Model):

    trial_start = DurationField()
    movement_start = DurationField()
    trial_stop = DurationField()


    def clean(self):
        from django.core.exceptions import ValidationError
        if not (self.movement_start >= self.trial_start):
            raise ValidationError('movement start must be >= trial start')
        if not (self.trial_stop >= self.movement_start):
            raise ValidationError('trial stop must be >= movement start')
        if not (self.trial_stop > self.trial_start):
            raise ValidationError('trial stop must be > trial start')

Мой метод clean() проверяет, находятся ли определенные значения в правильном диапазоне. Если пользователь забыл заполнить поле, например. movement_start, я получаю сообщение об ошибке:

can't compare datetime.timedelta to NoneType

Я удивлен, что получаю эту ошибку, так как исходная функция clean() должна улавливать эту пропущенную запись (ведь movement_start - обязательное поле). Итак, как я могу выполнить базовую проверку отсутствующих значений, и моя пользовательская проверка, находятся ли значения в определенных диапазонах? Можно ли это сделать с помощью метода модели clean(), или мне нужно использовать Forms?

EDIT1, чтобы сделать его более понятным: trial_start, movement_start и trial_stop - все обязательные поля. Мне нужно написать метод clean(), который сначала проверяет, что все три поля заполнены, а затем проверьте, находятся ли значения в определенном диапазоне.

Следующий код, например, НЕ работает, поскольку trial_start может быть пустым. Я хочу избежать необходимости проверять наличие каждого поля - django должен сделать это для меня.

class TrialForm(ModelForm):

    class Meta:
        model = Trial

    def clean_movement_start(self):
        movement_start = self.cleaned_data["movement_start"]
        trial_start = self.cleaned_data["trial_start"]
        if not (movement_start >= trial_start):
            raise forms.ValidationError('movement start must be >= trial start')
        return self.cleaned_data["movement_start"] 

EDIT2 Причина, по которой я хотел добавить эту проверку в метод модели clean(), заключается в том, что объекты, созданные в оболочке python, будут автоматически проверяться на правильные значения. Форма будет полезна для представлений, но мне нужна проверка значения и для оболочки.

4b9b3361

Ответ 1

Я предполагаю, что путь:

class TrialForm(ModelForm):

    class Meta:
        model = Trial

    def clean(self):

        data = self.cleaned_data
        if not ('movement_start' in data.keys() and 'trial_start' in data.keys()  and 'trial_stop' in data.keys()):
            raise forms.ValidationError("Please fill out missing fields.")

        trial_start = data['trial_start']
        movement_start = data['movement_start']
        trial_stop = data['trial_stop']

        if not (movement_start >= trial_start):
            raise forms.ValidationError('movement start must be >= trial start')

        if not (trial_stop >= movement_start):
            raise forms.ValidationError('trial stop must be >= movement start')

        if not (trial_stop > trial_start):
            raise forms.ValidationError('trial stop must be > trial start')

        return data

EDIT Недостатком этого подхода является то, что проверка значения будет работать, только если я создам объекты через форму. Объекты, созданные на оболочке python, не будут проверяться.

Ответ 2

Я знаю, что это уже поздно, но чтобы ответить, почему это может произойти для людей, которые здесь заканчиваются: нет "оригинальной чистой". Чистый метод - это крючок для пользовательской проверки, поэтому вы являетесь тем, кто предоставляет свой код. Не знаете, как OP использует чистый крючок, но: после его определения вы должны называть full_clean() над вашими моделями, чтобы Django полностью выполняла проверку модели. См. Подробности в документах для порядка, в котором он вызывает различные методы проверки, и https://docs.djangoproject.com/en/1.11/ref/models/instances/#validating-objects (возможно, важно отметить: full_clean() автоматически не вызывается моделью save(), которая является частью того, почему, когда вы используете оболочку и сохраняете сразу же, вы пропустите проверку)

(примечание ModelForms также имеют различные этапы проверки и вызовет модель full_clean: https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/#validation-on-a-modelform)

Ответ 3

Я борюсь с подобной проблемой, но с ForeignKey. В вашем случае я просто проверю, что поля не пусты, и я упростил бы ваши булевы выражения:

class Trial(models.Model):

    trial_start = DurationField()
    movement_start = DurationField()
    trial_stop = DurationField()


    def clean(self):
        from django.core.exceptions import ValidationError
        if self.trial_start:
            if self.movement_start and self.movement_start < self.trial_start:
                raise ValidationError('movement start must be >= trial start')
            if self.trial_stop:
                if self.trial_stop <= self.trial_start:
                    raise ValidationError('trial stop must be > trial start')
                if self.movement_start:
                    if self.trial_stop < self.movement_start:
                        raise ValidationError('trial stop must be >= movement start')