Ответ 1
Для OP или любого, кто там ищет, между этими полезными битами вам должно быть хорошо:
Есть ли способ сделать виджет администратора ArrayField возможным добавлять и удалять объекты? Кажется, что по умолчанию вместо него отображается только текстовое поле и используется разделение запятой для его значений.
Помимо неудобства, AFAICT в случае, когда базовое поле массива является Char/TextField, это не позволяет включать запятые в любой из текстов в массиве.
Для OP или любого, кто там ищет, между этими полезными битами вам должно быть хорошо:
Я не возражаю против этого (исходный код), но если вы используете PostgreSQL в качестве базы данных и готовы использовать реализацию ArrayField для Postgres, есть еще более простой вариант: подкласс ArrayField
в модель и переопределить виджет администратора по умолчанию. Ниже приведена базовая реализация (протестирована в Django 1.9, 1.10, 1.11, 2.0, 2.1 и 2.2):
models.py
from django import forms
from django.db import models
from django.contrib.postgres.fields import ArrayField
class ChoiceArrayField(ArrayField):
"""
A field that allows us to store an array of choices.
Uses Django Postgres ArrayField
and a MultipleChoiceField for its formfield.
"""
def formfield(self, **kwargs):
defaults = {
'form_class': forms.MultipleChoiceField,
'choices': self.base_field.choices,
}
defaults.update(kwargs)
# Skip our parent formfield implementation completely as we don't
# care for it.
# pylint:disable=bad-super-call
return super(ArrayField, self).formfield(**defaults)
FUNCTION_CHOICES = (
('0', 'Planning'),
('1', 'Operation'),
('2', 'Reporting'),
)
class FunctionModel(models.Model):
name = models.CharField(max_length=128, unique=True)
function = ChoiceArrayField(
base_field=models.CharField(max_length=256, choices=FUNCTION_CHOICES),
default=list)
django-select2
предлагает способ отображения ArrayField
с помощью Select2. В их документации приведен пример для ArrayField
:
Чтобы отобразить уже выбранные значения:
class ArrayFieldWidget(Select2TagWidget):
def render_options(self, *args, **kwargs):
try:
selected_choices, = args
except ValueError: # Signature contained `choices` prior to Django 1.10
choices, selected_choices = args
output = ['<option></option>' if not self.is_required and not self.allow_multiple_selected else '']
selected_choices = {force_text(v) for v in selected_choices.split(',')}
choices = {(v, v) for v in selected_choices}
for option_value, option_label in choices:
output.append(self.render_option(selected_choices, option_value, option_label))
return '\n'.join(output)
def value_from_datadict(self, data, files, name):
values = super().value_from_datadict(data, files, name)
return ",".join(values)
Чтобы добавить виджет в форму:
class MyForm(ModelForm):
class Meta:
fields = ['my_array_field']
widgets = {
'my_array_field': ArrayFieldWidget
}