[英]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=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')
)
在 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.