Виджет Django Jsonfield для ввода данных в формате: формы.Select (клавиша) - формы.TextInput (значение)
У меня возникают трудности с реализацией "удобного для пользователя" ввода JSON в форме.
У меня есть некоторая Item
модель, которая содержит attributes = JSONFIeld()
.
class ItemType(models.Model):
title = models.CharField()
class Item(models.Model):
title = models.CharField()
item_type = models.ForeignKey(ItemType)
attributes = models.JSONField()
Чтобы сохранить определенную "схему" в рамках одной ItemType
, я добавил модели:
class ItemAttribute(models.Model):
title = models.CharField(max_length=100, unique=True)
class ItemAttributeSpec(models.Model):
item_type = models.ForeignKey(ItemType)
attribute = models.ForeignKey(ItemAttribute)
required = models.BooleanField(default=False)
choices = models.JSONField(default=list)
Итак, цель для реализации:
Предоставьте набор пар атрибутов key/value
, где key
поля JSON будет forms.Select()
или просто label
(не имеет большого значения, поскольку я могу управлять реализацией этой функции) и value
- это входные данные. Таким образом, каждый отдельный Item
, например, будет иметь все атрибуты, связанные с типом, для ввода. Как правило, это какой-то набор форм в одном экземпляре формы.
Использование вспомогательных моделей для определения схемы, но без указания значения, - это, по сути, все хлопоты, связанные с настройкой EAV, практически без каких-либо преимуществ, IMO.
Вы бы вели двойную бухгалтерию, сохраняя ключи в формате JSON на Item
в дополнение к определению ключей и всех их метаданных во всех этих помощниках. Это делает помощников в значительной степени бесполезными, за исключением целей проверки схемы, и наверняка найдутся более простые способы сделать это, если только у вас нет особых бизнес-потребностей.
Вместо этого, вот решение в одной форме, которое не использует никаких вспомогательных моделей, а схема определяется dict
во время выполнения:
class DynamicKVForm(forms.Form):
def __init__(self, *args, **kwargs):
kv_pairs = kwargs.pop('json_schema', [])
super().__init__(*args, **kwargs)
for field in kv_pairs:
key = field['key']
field_kwargs = {
'label': field.get('label', key.capitalize()),
'required': field.get('required', False),
'help_text': field.get('help_text', ''), # <-- You can optionally pass `help_text` in the input to override this on a per-field basis
'initial': field.get('initial', None), # <-- Same for this one
}
self.fields[key] = forms.CharField(**field_kwargs)
Вы можете расширить эту функциональность, добавив в схему поле, в котором вы определяете тип виджета и т.д., И использовать эту информацию для динамической выборки виджетов, а не для создания всего CharField
.
Использование:
form = DynamicKVForm(
json_schema=[
{"key": "name", "label": "Full name", "required": True},
{"key": "email", "label": "Email address", "required": True},
]
)
Если вам нужно сохранить схему в базе данных, одним из простых решений является сохранение ее в Item
в отдельном атрибуте JSONField
.