Как добавить optgroups в django ModelMultipleChoiceField? - PullRequest
2 голосов
/ 17 сентября 2010

У меня есть форма с ModelMultipleChoiceField для списка категорий. Я хотел бы сгруппировать категории, используя поле Category.group.

Я думал, что, изменив поле. choices в функции init это сделает трюк

class CategoriesField(forms.ModelMultipleChoiceField):
    def __init__(self, queryset, **kwargs):
        super(forms.ModelMultipleChoiceField, self).__init__(queryset, **kwargs)
        self.queryset = queryset.select_related()
        self.to_field_name=None

        group = None
        list = []
        self.choices = []

        for category in queryset:
            if not group:
                group = category.group

            if group != category.group:
                self.choices.append((group.title, list))
                group = category.group
                list = [(category.id, category.name)]
            else:
                list.append((category.id, category.name))
        try:
            self.choices.append((group.title, list))
        except:
            pass

Но ModelChoiceIterator по-прежнему стирает информацию self.choices, установленную в функции __init__.

Как я могу сделать это правильно?

Ответы [ 2 ]

0 голосов
/ 20 декабря 2016

Я нашел этот вопрос / ответ полезным, но сильно изменил код. Проблема с приведенным выше кодом состоит в том, что он генерирует список только один раз, а затем кэшируется (набор запросов используется только один раз). Мой код предназначен для объектов "Article", которые упорядочены по "профилю" (он же автор), но любой должен иметь возможность изменять его для своего использования. Он использует новый набор запросов каждый раз, поэтому он обновляется без перезапуска (если вы не передадите cache_choices=True в ArticleMultipleChoiceField, а затем он кешируется).

class ArticleChoiceIterator(forms.models.ModelChoiceIterator):
    def __iter__(self):
        if self.field.empty_label is not None:
            yield ("", self.field.empty_label)
        if self.field.cache_choices:
            if self.field.choice_cache is None:
                last_profile = None
                self.field.choice_cache = []
                for article in self.queryset.all():
                    if last_profile != article.profile:
                        last_profile = article.profile
                        article_list = []
                        self.field.choice_cache.append((article.profile.name, article_list))
                    article_list.append(self.choice(article))
            for choice in self.field.choice_cache:
                yield choice
        else:
            last_profile = None
            article_choices = []
            for article in self.queryset.all():
                if last_profile != article.profile:
                    if article_choices:
                        yield (getattr(last_profile, 'name', ''), article_choices)
                    last_profile = article.profile
                    article_choices = []
                article_choices.append(self.choice(article))
            if article_choices:
                yield (getattr(last_profile, 'name', ''), article_choices)


class ArticleMultipleChoiceField(forms.ModelMultipleChoiceField):
    # make sure queryset is ordered by profile first!
    def __init__(self, queryset, **kwargs):
        super(ArticleMultipleChoiceField, self).__init__(queryset, **kwargs)
        self.queryset = queryset.select_related('profile')
        self._choices = ArticleChoiceIterator(self)


class PackageForm(forms.ModelForm):
    articles = ArticleMultipleChoiceField(
        queryset=Article.objects.order_by('profile__name', 'title')
    )
0 голосов
/ 17 сентября 2010

На самом деле это работает, как я только что объяснил, но не забывайте эту часть:

class ProfilForm(ModelForm):
    categories  = CategoriesField(queryset=Category.objects.all().order_by('group'), label=_(u'Catégories'))
...