如何将 optgroups 添加到 django ModelMultipleChoiceField?

Posted

技术标签:

【中文标题】如何将 optgroups 添加到 django ModelMultipleChoiceField?【英文标题】:How to add optgroups to a django ModelMultipleChoiceField? 【发布时间】:2011-04-13 19:41:39 【问题描述】:

我有一个带有ModelMultipleChoiceField 类别列表的表格。 我想使用Category.group 字段对类别进行分组。

我认为通过在 init 函数中更改字段.choices 会成功

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 仍然会擦除__init__ 函数中设置的self.choices 信息。

我怎样才能以正确的方式做到这一点?

【问题讨论】:

【参考方案1】:

实际上它就像我刚刚解释的那样工作,但不要忘记那部分:

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

【讨论】:

【参考方案2】:

你的代码对我有用,谢谢!也可以与 models.ManyToManyField 一起使用,这对其他人可能也很有趣:

from django.db import models

class CustomManyToManyField(models.ManyToManyField):
    def formfield(self, *args, **kwargs):
        kwargs["form_class"] = CategoriesField
        return super().formfield(**kwargs)

我遇到了同样的缓存错误,并且还通过将整个选择更新放在迭代器中来修复它:

class CustomModelChoiceIterator(forms.models.ModelChoiceIterator):
    def __iter__(self):
        group = ""
        subgroup = []
        for category in self.queryset:
            if not group:
                group = category.group

            if group != category.group:
                yield (group.title, subgroup)
                group = category.group
                subgroup = [(category.id, category.name)]
            else:
                subgroup.append((category.id, category.name))
        yield (group.title, subgroup)


class CategoriesField(forms.ModelMultipleChoiceField):
    iterator = CustomModelChoiceIterator

【讨论】:

【参考方案3】:

我发现这个问题/答案很有帮助,但对代码进行了很多更改。上面代码的问题是它只生成了一次列表,然后就被缓存了(查询集只使用一次)。我的代码适用于按“个人资料”(又名作者)排序的“文章”对象,但任何人都应该能够修改它以供使用。它每次都使用一个新的查询集,因此无需重新启动即可更新(除非您将 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')
    )

【讨论】:

以上是关于如何将 optgroups 添加到 django ModelMultipleChoiceField?的主要内容,如果未能解决你的问题,请参考以下文章

如何添加 optgroup do dijit.form.Select 或其他小部件类型

如何使用 JSON 在 select2 中设置 optgroup

将 select2.js 与多个选择 optgroup 和 knockoutJS 一起使用

动态添加 optgroup 列表

将 <optgroup> 与 form.fields.queryset 一起使用?

在 Select2 中动态添加选项和 optgroup