Почему django's model.save () не вызывает full_clean ()?

106

Мне просто интересно, если кто-нибудь знает, есть ли хорошая причина, почему джанго-орм не называет "full_clean" на модели, если он не сохраняется как часть модельной формы.

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

(ПРИМЕЧАНИЕ: котировка обновлена ​​для Django 1.6... предыдущие django docs имели оговорку и о ModelForms.)

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

Я знаю, как заставить все работать правильно, я просто ищу объяснения.

  • 7
    Большое спасибо за этот вопрос, он помешал мне биться головой об стену гораздо больше времени. Я создал миксин, который может помочь другим. Проверьте суть: gist.github.com/glarrain/5448253
  • 0
    И, наконец, я использую сигнал, чтобы поймать хук pre_save и сделать full_clean на всех пойманных моделях.
Теги:
django-models
django-validation

5 ответов

42
Лучший ответ

AFAIK, это связано с обратной совместимостью. Существуют также проблемы с ModelForms с исключенными полями, моделями со значениями по умолчанию, сигналами pre_save() и т.д.

Источники, на которые вы можете обратить внимание:

  • 2
    Самый полезный отрывок (IMHO) из второй ссылки: «Разработка« автоматической »опции проверки, которая достаточно проста, чтобы быть полезной, и достаточно надежна для обработки всех крайних случаев, - если это вообще возможно - гораздо больше, чем может быть достигнуто на временном интервале 1.2. Следовательно, на данный момент Django не имеет ничего подобного и не будет иметь его в 1.2. Если вы думаете, что можете заставить его работать на 1.3, лучше всего поднять предложение, включая хотя бы пример кода, а также объяснение того, как вы будете делать его простым и надежным. "
  • 1
    Попробуйте это: github.com/danielgatis/django-smart-save
18

Из-за совместимости, учитывая, что в ядре django функция auto clean on save не включена.

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

from django.dispatch import receiver
from django.db.models.signals import pre_save, post_save

@receiver(pre_save)
def pre_save_handler(sender, instance, *args, **kwargs):
    instance.full_clean()
  • 1
    Почему это лучше (или хуже), чем переопределение метода save в некоторой BaseModel (от которой все остальные наследуют), чтобы сначала вызвать full_clean, а затем вызвать super ()?
  • 0
    @J__ Очевидно, этот метод применяется ко всем моделям, а не к конкретной, поэтому вы можете писать один раз, использовать везде. Если вы переопределите некоторую BaseModel, вы должны написать для каждой модели.
Показать ещё 7 комментариев
6

Самый простой способ вызова метода full_clean - это просто переопределить метод save в model:

def save(self, *args, **kwargs):
    self.full_clean()
    return super(YourModel, self).save(*args, **kwargs)
  • 0
    Почему это лучше (или хуже), чем использовать сигнал?
  • 0
    @J__ см. Ответ stackoverflow.com/a/171703/6077223
Показать ещё 1 комментарий
1

Вместо того, чтобы вставлять фрагмент кода, который объявляет приемник, мы можем использовать приложение как INSTALLED_APPS в разделе settings.py

INSTALLED_APPS = [
    # ...
    'django_fullclean',
    # your apps here,
]

До этого вам может потребоваться установить django-fullclean с помощью PyPI:

pip install django-fullclean
  • 9
    Зачем вам pip install приложение с четырьмя строками кода (проверьте исходный код ) вместо написания этих строк самостоятельно?
0

Если у вас есть модель, которую вы хотите обеспечить, по крайней мере, одно отношение FK, и вы не хотите использовать null=False, потому что для этого требуется установка FK по умолчанию (который будет представлять собой данные мусора), лучший способ я Придумаем добавить пользовательские методы .clean() и .save(). .clean() вызывает ошибку проверки, а .save() вызывает чистоту. Таким образом, целостность обеспечивается как от форм, так и от другого кода вызова, командной строки и тестов. Без этого нет (AFAICT) никакого способа написать тест, который гарантирует, что модель имеет отношение FK к специально выбранной (не по умолчанию) другой модели.

class Payer(models.Model):

    name = models.CharField(blank=True, max_length=100)
    # Nullable, but will enforce FK in clean/save:
    payer_group = models.ForeignKey(PayerGroup, null=True, blank=True,)

    def clean(self):
        # Ensure every Payer is in a PayerGroup (but only via forms)
        if not self.payer_group:
            raise ValidationError(
                {'payer_group': 'Each Payer must belong to a PayerGroup.'})

    def save(self, *args, **kwargs):
        self.full_clean()
        return super().save(*args, **kwargs)

    def __str__(self):
        return self.name

Ещё вопросы

Сообщество Overcoder
Наверх
Меню