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" ...>