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

Проверка полей модели Django

Где должна выполняться проверка полей модели в django?

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

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

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

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

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

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

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)

Возможно, я что-то упустил, и это можно сделать проще (и чище)?

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

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

В то время как это не касается сундука, Malcolm "решение для проверки модели для бедных людей" , вероятно, является самым чистым решением, чтобы избежать повторения.

Ответ 4

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