Django forms.Form, отражающие ограничения полей свойств

Я реализую Django Form ведьма должна содержать поле 'fieldA' из modelA:

class ModelA(models.Model):
    fieldA =  models.CharField(max_length=8)
    ...

Мой вопрос: Есть ли способ иметь Django форму, которая будет автоматически обрабатывать валидацию поляА (проверять max_length)? Я знаю, что могу использовать form.ModelFormclass, ссылающийся на ModelA, но тогда форма будет отражать все поля ModelA. Я хотел бы использовать простые forms.Form.

Я ищу решение типа:

class formX(forms.Form):
    fieldA = forms.CharField(**modelA.fieldA.constraints)
    fieldB = ... some other fields not related to ModelA ...
    .... even more fields

Возможно, этот вопрос - проблема XY, но позвольте мне попробовать...

Прямой вопрос: получить ограничения на поля из существующей модели

from django import forms
from django.db import models

class Foo(models.Model):
    x = models.CharField(max_length=30)
    y = models.IntegerField(null=True)

class FooForm(forms.Form):
    foo_x = forms.CharField(max_length=Foo._meta.get_field('x').max_length)

Вы можете получить прямой доступ к полю двумя способами:

  1. ModelClass.field_name.field (своего рода хак, ModelClass.field_name является django.db.models.query_utils.DeferredAttribute)
  2. ModelClass._meta.get_field('field_name') (лучший способ, описан где-то в документации)

Однако, при таком способе вам придется а) обновлять форму при добавлении ограничений на поля или б) указывать все атрибуты заранее (max_length, min_length, verbose_name, blank и т.д.), что делает объявление FooForm.foo_x слишком многословным.

Альтернативы

Полевое подмножество

Прежде всего, если вам нужно подмножество полей Foo, используйте ModelForm и укажите их:

class FooForm(forms.ModelForm):
    class Meta:
        fields = ('x',)

Теперь у вас есть форма, содержащая только x поле.

Добавьте некоторые поля

Если вы хотите добавить поля в эту форму (которые не связаны с другой моделью), сделайте это:

class FooForm(forms.ModelForm):
    another_field = forms.IntegerField()

    class Meta:
        fields = ('x',)

    def clean_another_field(self):
        data = self.cleaned_data['another_field'] 
        if data != 42:
            raise ValidationError('Not an answer!')  # i18n should be here
        return data

Также вы можете переопределить clean и save методы для других целей, документация хорошо объясняет это.

Смешивание полей из разных моделей

Если вам нужно, чтобы поля двух разных моделей присутствовали в одной форме, то это не так. В этом случае вам нужны две отдельные формы, плюс некоторая логика интервалидации вне этих форм (например, как метод представления или как другой класс, который не является формой). Возможно, то, что вам нужно, это inline formset, он не представляет две смешанные формы, но по крайней мере имеет некоторую межмодельную связь.

Я нашел способ, как добиться валидации поля формы, отражающей ограничения от поля модели.

class Foo(models.Model):
    x = models.CharField(max_length=30)
    y = models.IntegerField(null=True)

class FooForm(forms.Form):
    foo_x = forms.CharField(validators=Foo._meta.get_field('x').validators)

Таким образом, форма будет уважать max_length валидатор атрибута x или любой другой определенный валидатор.

Вернуться на верх