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

Правильный способ проверки объектов модели Django?

Я все еще пытаюсь понять правильный способ проверки объекта модели Django с использованием настраиваемого валидатора на уровне модели. Я знаю, что проверка обычно выполняется в форме или в форме модели. Тем не менее, я хочу обеспечить целостность моих данных на уровне модели, если я взаимодействую с ним через ORM в оболочке Python. Здесь мой текущий подход:

from django.db import models
from django.core import validators
from django.core exceptions import ValidationError


def validate_gender(value):
    """ Custom validator """
    if not value in ('m', 'f', 'M', 'F'):
        raise ValidationError(u'%s is not a valid value for gender.' % value)


class Person(models.Model):
    name = models.CharField(max_length=128)
    age = models.IntegerField()
    gender = models.CharField(maxlength=1, validators=[validate_gender])

    def save(self, *args, **kwargs):
        """ Override Person save """
        self.full_clean(exclude=None)
        super(Person, self).save(*args, **kwargs)

Вот мои вопросы:

  • Должен ли я создать пользовательскую функцию проверки, назначить ее как валидатор, а затем переопределить функцию Person save(), как я уже сделал выше? (Кстати, я знаю, что могу проверить мои варианты выбора пола, используя опцию "выбор", но я создал "validate_gender" для иллюстрации).

  • Если я действительно хочу обеспечить целостность своих данных, должен ли я не только записывать модульные тесты Django для тестирования на уровне модели, но и эквивалентные модульные тесты уровня базы данных с использованием Python/Psycopg? Я заметил, что модульные тесты Django, которые повышают ValidationErrors, проверяют только модель понимания схемы базы данных с использованием копии базы данных. Даже если бы я использовал Юг для миграции, любые ограничения на уровне базы данных ограничены тем, что Django может понять и перевести в ограничение Postgres. Если мне нужно настраиваемое ограничение, которое Django не может реплицировать, я могу потенциально ввести данные в свою базу данных, которые нарушают это ограничение, если я взаимодействую с базой данных напрямую через терминал psql.

Спасибо!

4b9b3361

Ответ 1

У меня было аналогичное непонимание ORM, когда я впервые начал с Django.

1) Нет, не ставьте self.full_clean() внутри save. Либо

A) используйте ModelForm (что вызовет все те же проверки) - note: ModelForm.is_valid() не будет вызывать Model.full_clean явно, но будет выполнять те же проверки, что и Model.full_clean). Пример:

class PersonForm(forms.ModelForm):
    class Meta:
        model = Person

def add_person(request):
    if request.method == 'POST':
        form = PersonForm(request.POST, request.FILES)
        if form.is_valid():  # Performs your validation, including ``validate_gender``
            person = form.save()
            return redirect('some-other-view')
    else:
        form = PersonForm()
        # ... return response with ``form`` in the context for rendering in a template

Также обратите внимание, что формы не используются только в представлениях, которые отображают их в шаблонах - они отлично подходят для любого вида использования, включая API и т.д. После запуска form.is_valid() и получения ошибок вы будете иметь form.errors, который является словарем, содержащим все ошибки в форме, включая ключ с именем '__all__', который будет содержать ошибки без полей.

B) Просто используйте model_instance.full_clean() в своем представлении (или другом уровне логического приложения) вместо использования формы, но формы - это хорошая абстракция для этого.

2) У меня на самом деле нет решения, но я никогда не сталкивался с такой проблемой, даже в крупных проектах (текущий проект, который я работаю с моей компанией, имеет 146 таблиц), и я не подозреваю это будет проблемой и в вашем случае.