django - добавление атрибутов к полям MultiValueField / MultiWidget

Все,

Мне удалось заставить MultiValueField и MultiValueWidget работать. Но, кроме "выбора", я не могу добавить атрибуты (например, "метка" или "начальный") к подполям, которые составляют MultiValueField.

Вот мой (упрощенный) код:

class MyMultiWidget(django.forms.widgets.MultiWidget):
    def __init__(self,*args,**kwargs):
        myChoices = kwargs.pop("choices",[])
        widgets = (
            django.forms.fields.TextInput(),
            django.forms.fields.TextInput(),
            django.forms.fields.Select(choices=myChoices),
        )
        super(MyMultiWidget, self).__init__(widgets,*args,**kwargs)        

class MyMultiValueField(django.forms.fields.MultiValueField):
    widget = MyMultiWidget

    def __init__(self,*args,**kwargs):

        myLabel = "my label"
        myInitial = "my initial value"
        myChoices = [("a","a"),("b","b")]

        fields = (
            django.forms.fields.CharField(label=myLabel),
            django.forms.fields.CharField(initial=myInitial),
            django.forms.fields.ChoiceField(choices=myChoices),
        )
        super(MyMultiValueField,self).__init__(fields,*args,**kwargs)
        self.widget=MyMultiWidget(choices=myChoices)

class MyField(models.Field):

    def formfield(self,*args,**kwargs):
        return MyMultiValueField()

class MyModel(django.models.Model):
    myField = MyField(blank=True)

MyForm = modelform_factory(MyModel)

Поле myField MyModel почти правильно отображается в MyForm; Он показывает три виджета: два TextInputs и Select. Последний ограничен соответствующими вариантами. Но первые два не имеют своих меток или начальных значений.

Любые предложения о том, что я делаю не так?

Благодарю.

4 ответа

Вы должны определить format_output функция вашего виджета - см.: https://docs.djangoproject.com/en/dev/ref/forms/widgets/

Это позволяет вам форматировать html формы так, как вам нравится. Я думаю, что по умолчанию просто объединить элементы поля.

Ответ, предоставленный Беном, немного хакерский, я бы передал начальное значение, используя 'attrs':

forms.TextInput(attrs={'value': 'some text'})

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

Я знаю, что этой ветке уже более 9 лет, но я только что сам решил эту проблему (Python 3.9, Django 3.2).

В итоге я определил кортеж CharFieldобъекты, которые необходимо передать конструктору. Объекты CharField были созданы с атрибутами, которые я хотел передать в MultiValueField(включая атрибуты & и для каждого).

placeholderявляется довольно эффективной меткой для каждого поля и может использоваться по умолчанию.

Обратите внимание, что вы не можете жестко кодировать valueв поле, если вы используете общие представления на основе классов на ModelFormпотому что это приводит к тому, что поле перезаписывается жестко заданным значением при открытии UpdateView. Чтобы учесть это, вы должны установить значение по умолчанию для поля в модели (я использовал JSONField), затем возьмите соответствующие данные из экземпляра формы после его инициализации и передайте их конструктору поля в кортеже multi_fields.

РЕДАКТИРОВАТЬ: не забудьте включить поле модели в форму Metaучебный класс. Я узнал на собственном горьком опыте, что ваша форма не сохранит новые значения, если вы пропустите это.

Затем я передал этот кортеж конструктору как fieldsаргумент и использовали списки в кортеже для динамического определения widget(пользовательский MultiWidget, созданный с пониманием списка) и help_textатрибуты.

      # MODELS.PY
from django import models


def default_multi_values():
    return {
        'Field1': 'Field1Value',
        'Field2': 'Field2Value'
    }


class ExampleModel(models.Model):
    example_field = models.JSONField(
        default=default_multi_values()
    )
      # FORMS.PY
from django import forms


class CustomMultiWidget(forms.widgets.MultiWidget):
    
    def decompress(self, value):
        **do decompress**


class CustomMultiValueField(forms.MultiValueField):
    widget = CustomMultiWidget

    def compress(self, data_list):
        **do compress**


class CustomModelForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        mf_values = self.instance.multi_value_field_here

        multi_fields = (
            forms.CharField(
                help_text='HelpText1',
                widget=forms.TextInput({
                    'placeholder': 'Placeholder1',
                    'value': mf_values['Field1']
                })
            ),
            forms.CharField(
                help_text='HelpText2',
                widget=forms.TextInput({
                    'placeholder': 'Placeholder2',
                    'value': mf_values['Field2']
                })
            ),
        )

        self.fields['multi_value_field_here'] = CustomMultiValueField(
            fields=multi_fields,
            widget=ColumnHeadersWidget(
                widgets=[field.widget for field in multi_fields],
            # Display an ordered list below the MultiWidget 
            # constructed from help_text messages from each consecutive field.
            help_text=
                f"<u><strong>MultiField Guide</strong></u></br>"
                f"{'</br>'.join(f'{multi_fields.index(field) + 1}: {field.help_text}' for field in multi_fields]}"
            )
        )

        class Meta:
            model = ExampleModel
            fields = [
                'example_field'
            ]

@george прав, что value можно определить статически, но вы также можете переопределить get_context чтобы выяснить значение во время выполнения.

class MyInput(forms.CharField):
    def get_context(self, name, value, attrs):
        return super().get_context('some_name', 'some_value', attrs)

Окажет

<input type="text" name="some_name" value="some_value" ...>
Другие вопросы по тегам