簡體   English   中英

如何將 optgroups 添加到 django ModelMultipleChoiceField?

[英]How to add optgroups to a django ModelMultipleChoiceField?

我有一個帶有ModelMultipleChoiceField的表格來列出類別。 我想使用Category.group字段對類別進行分組。

我認為通過改變領域。 初始化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__ function 中設置的self.choices信息。

我怎樣才能以正確的方式做到這一點?

實際上它就像我剛剛解釋的那樣工作,但不要忘記那部分:

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

您的代碼對我有用,謝謝! 也可以與 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

我發現這個問題/答案很有幫助,但對代碼進行了大量更改。 上面代碼的問題在於它只生成一次列表,然后將其緩存(查詢集僅使用一次)。 我的代碼用於按“個人資料”(又名作者)排序的“文章”對象,但任何人都應該能夠修改它以供他們使用。 它采用每次所以它不重啟更新(除非你通過一個新的查詢集cache_choices=TrueArticleMultipleChoiceField ,然后它的高速緩存)。

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')
    )

在 2022 年嘗試:

class GroupedModelChoiceIterator(ModelChoiceIterator):
    def __init__(self, field, groupby):
        self.groupby = groupby
        super().__init__(field)

    def __iter__(self):
        if self.field.empty_label is not None:
            yield ("", self.field.empty_label)
        queryset = self.queryset

        # Can't use iterator() when queryset uses prefetch_related()
        if not queryset._prefetch_related_lookups:
            queryset = queryset.iterator()
        for group, objs in groupby(queryset, self.groupby):
            yield (group, [self.choice(obj) for obj in objs])


class GroupedModelMultipleChoiceField(ModelMultipleChoiceField):
    def __init__(self, *args, choices_groupby, **kwargs):
        if isinstance(choices_groupby, str):
            choices_groupby = attrgetter(choices_groupby)
        elif not callable(choices_groupby):
            raise TypeError('choices_groupby must either be a str or a callable accepting a single argument')
        self.iterator = partial(GroupedModelChoiceIterator, groupby=choices_groupby)
        super().__init__(*args, **kwargs)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM