Проверка полей модели Django - PullRequest
58 голосов
/ 26 октября 2009

Куда должна идти проверка полей модели в django?

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

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

  • когда абсолютно необходимо убедиться, что пустая строка не записывается в базу данных (пусто = аргумент False ключевое слово здесь не работает, он только для проверки формы)
  • когда необходимо убедиться, что аргумент ключевого слова "выборы" соблюдается на уровне БД, а не только в интерфейсе администратора (эмуляция типа данных 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 ]

61 голосов
/ 26 октября 2009

Django имеет систему проверки модели , начиная с версии 1.2.

В комментариях sebpiq говорит: «Хорошо, теперь есть место для проверки модели ... за исключением того, что она запускается только при использовании ModelForm! Поэтому остается вопрос, когда необходимо обеспечить, чтобы проверка выполнялась db-level, что делать? Где позвонить full_clean? "

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

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

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

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

6 голосов
/ 03 марта 2011

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

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/)

3 голосов
/ 26 октября 2009

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

Хотя это не касается ствола, «Решение по проверке модели для бедного человека» Малколма , вероятно, является самым чистым решением, чтобы избежать повторения.

1 голос
/ 26 октября 2009

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

...