如何将optgroup添加到django ModelMultipleChoiceField?

时间:2010-09-17 16:21:32

标签: python django django-forms properties

我的表单中包含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仍然会删除self.choices函数中设置的__init__信息。

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

3 个答案:

答案 0 :(得分:1)

您的代码对我有用,谢谢!也可以与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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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