Могу ли я переопределить стандартное поле CharField на ChoiceField в ModelForm?

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

Однако есть несколько полей, для которых человеческий интерфейс должен быть ChoiceField. Могу ли я переопределить тип поля формы по умолчанию (CharField)? (Чтобы уточнить, поле модели не является и не может быть ограничено выбором, потому что исторические данные должны храниться. Я хочу ограничить только будущие добавления в таблицу через представление create).

class HorribleTable( models.Model):
    ...
    foo = models.CharField( max_length=16, blank=True, ... )
    ... 

class AddHorribleTableEntryForm( models.Model)
     class Meta:
          model = HorribleTable
          fields = '__all__' # or a list if it helps
      
     FOO_CHOICES = (('square', 'Square'), ('rect', 'Rectangular'), ('circle', 'Circular') )

     ...?

Возможно, вы могли бы выводить формы вручную, передавая опции через контекст и оформляя поля в html.

Посмотрите здесь: https://docs.djangoproject.com/en/4.0/topics/forms/#rendering-fields-manually

Я думаю, что вы можете легко установить ваше пользовательское поле формы, если оно будет соответствовать типу данных, установленному в вашей модели (например, не устанавливать варианты длиннее, чем max_length для CharField и т.д.). Сделайте следующее, где foo - это имя поля в вашей модели:

class AddHorribleTableEntryForm(forms.ModelForm):
    foo  = forms.ChoiceField(choices=FOO_CHOICES)

    class Meta:
        model = HorribleTable
        ...

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

UPDATE

Другой подход заключается в переопределении метода init формы. Таким образом, вы сможете обрабатывать оба действия (создание и обновление) в рамках одной формы. Пусть пользователь выбирает из поля выбора при создании объекта. И отображать как обычное поле модели для существующих объектов:

class AddHorribleTableEntryForm(forms.ModelForm):
    foo  = forms.ChoiceField(choices=FOO_CHOICES)

    class Meta:
        model = HorribleTable
        fields = '__all__' # or a list if it helps

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        instance = kwargs.get("instance", None)
        if instance is None:
            self.fields["foo"].widget = forms.widgets.Select(choices=self.FOO_CHOICES)
Вернуться на верх