Отобразить разделенный запятыми список элементов ManyToMany в поле Charfield в ModelForm
У меня есть модель, содержащая поле ManyToMany для таблицы "Теги". Поскольку эта таблица может быть огромной, я не хочу отображать выборку в форме, а список тегов, разделенных запятой, предоставленный символом (я полагаю).
При сохранении я бы разделил список по запятой, а затем добавил их один за другим (используя get_or_create). Я уже сделал это.
Но когда я хочу изменить данные, вместо списка тегов у меня появляется список идентификаторов.
Как я могу отобразить список разделенных запятыми тегов? Должен ли я создать новое конкретное поле для этого? или уже есть что то, что я ищу?
Спасибо за вашу помощь!
1 ответ
Вы захотите создать собственный виджет (я не знаю встроенного виджета, который будет делать именно то, что вы хотите). Наиболее полезными примерами, вероятно, будут виджеты, поставляемые с Django (в forms/widgets.py). Вы также можете увидеть пример создания собственного виджета здесь.
Я немного поиграл, и после адаптации встроенного Input
виджет это то, что я придумал; Я провел некоторое тестирование, и оно работает для меня:
class CommaTags(Widget):
def render(self, name, value, attrs=None):
final_attrs = self.build_attrs(attrs, type='text', name=name)
objects = []
for each in value:
try:
object = Tag.objects.get(pk=each)
except:
continue
objects.append(object)
values = []
for each in objects:
values.append(str(each))
value = ', '.join(values)
if value: # only add 'value' if it's nonempty
final_attrs['value'] = force_unicode(value)
return mark_safe(u'<input%s />' % flatatt(final_attrs))
Обратите внимание, что в этом примере виджет жестко задан для использования гипотетического Tag
модель, и она просто использует str()
метод каждого объекта как то, что будет отображаться в списке через запятую. Возможно, вы захотите изменить их в соответствии с вашими потребностями. Кроме того, у меня это было прямо в файле forms / widgets.py, поэтому, если вы поместите его в другое место (как вы, вероятно, должны), вам нужно будет импортировать несколько вещей, которые я использовал.
Создав это, вы можете указать его в качестве виджета для вашего ModelMultipleChoiceField в вашей форме, например так:
from django import forms
class TagForm(forms.ModelForm):
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all(),
widget=CommaTags)
class Meta:
model = Tag
Приведенный выше код может использовать запросы более оптимальным образом, например
class CommaTags(Widget): def render(self, name, value, attrs=None): value = Tag.objects.filter(pk__in=each) \ .exclude(name__exact='') \ .values_list("name") \ .join(", ") if value: final_attrs['value'] = force_unicode(value) return mark_safe(u'<input%s />' % flatatt(final_attrs))