Отобразить разделенный запятыми список элементов 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))
Другие вопросы по тегам