Модели Django валидация полей


где проверки модель поля пойти в Джанго?

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

возможные варианты использования:

  • когда абсолютно необходимо убедиться, что пустая строка не записывается в базу данных (blank=False аргумент ключевого слова здесь не работает, он предназначен только для проверки формы)
  • когда необходимо убедиться, что аргумент ключевого слова "choices" уважается на уровне БД, а не только в интерфейсе администратора (вид эмуляции типа данных enum)

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

возможные реализации

на уровне поля:

class CustomField(models.CharField):
    __metaclass__ = models.SubfieldBase
    def to_python(self, value):
        if not value:
            raise IntegrityError(_('Empty string not allowed'))
        return models.CharField.to_python(self, value)

на уровне модели:

class MyModel(models.Model)
    FIELD1_CHOICES = ['foo', 'bar', 'baz']
    field1 = models.CharField(max_length=255, 
               choices=[(item,item) for item in FIELD1_CHOICES])

    def save(self, force_insert=False, force_update=False):
        if self.field1 not in MyModel.FIELD1_CHOICES:
            raise IntegrityError(_('Invalid value of field1'))
        # this can, of course, be made more generic
        models.Model.save(self, force_insert, force_update)

возможно, мне чего-то не хватает и это можно сделать проще (и чище)?

4 54

4 ответа:

у Джанго есть модель проверки система на месте с версии 1.2.

в комментариях sebpiq говорит: "Хорошо ,теперь есть место для проверки модели... за исключением того, что он запускается только при использовании ModelForm! Поэтому остается вопрос, когда необходимо обеспечить соблюдение валидации на уровне БД, что вы должны делать? Куда звонить full_clean?"

это невозможно с помощью проверки на уровне Python, чтобы гарантировать, что проверка соблюдается на уровень дБ. Ближайший, вероятно, позвонить full_clean в переопределенном save метод. Это не делается по умолчанию, потому что это означает, что все, кто вызывает этот метод сохранения, теперь должны быть готовы поймать и обработать ValidationError.

но даже если вы это сделаете, кто-то все равно может обновить экземпляры модели оптом с помощью queryset.update(), что позволит обойти эту проверку. Нет никакого способа, чтобы Django мог реализовать разумно эффективный queryset.update() который все еще может выполнять проверку на уровне Python на каждом обновленный объект.

единственный способ действительно гарантировать целостность уровня БД - через ограничения уровня БД; любая проверка, которую вы делаете через ORM, требует, чтобы автор кода приложения знал, когда проверка выполняется (и обрабатывает ошибки проверки).

вот почему проверка модели по умолчанию применяется только в ModelForm - потому что в ModelForm уже есть очевидный способ обработки ValidationError.

Я думаю, что вы хотите этого ->

from django.db.models.signals import pre_save

def validate_model(sender, **kwargs):
    if 'raw' in kwargs and not kwargs['raw']:
        kwargs['instance'].full_clean()

pre_save.connect(validate_model, dispatch_uid='validate_models')

(скопировано из http://djangosnippets.org/snippets/2319/)

основная проблема для этого заключается в том, что проверка должна происходить на моделях. Это обсуждалось в течение довольно долгого времени в django (проверка модели формы поиска в списке рассылки dev). Это приводит либо к дублированию, либо к тому, что ускользает от проверки перед попаданием в БД.

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

Если я понимаю вас "ясно" - вы должны переопределить функцию get_db_prep_save вместо to_python