我有一个数据集,用户可能需要编辑旧记录,但选择也必须限于一组“活动”值。这意味着,当选择包含非活动值的实例时,需要将旧选项添加到ModelChoiceField的查询集中。
在我看来,实现此目标的理想方法是将ModelChoiceField子类化,但是我似乎找不到在ModelChoiceField中插入实例数据的插入点。 我可以通过在forms.py中设置queryset来使其工作,但是我有大量的字段,这是必需的,并且确实希望有更多的pythonic / DRY解决方案。
例如:
models.py
class ActiveChoiceModel(models.Model):
name = models.CharField(max_length=10)
active = models.NullBooleanField(default=False)
class MyModel(models.Model):
fk_activechoicemodel = models.ForeignKey(to='mydb.ActiveChoiceModel')
ModelChoiceField的查询集应为:
ActiveChoiceModel.objects.filter(active=True) | ActiveChoiceModel.objects.filter(pk=instance.fk_activechoicemodel.id)
这可以在form.py中实现为:
Class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
if self.instance.fk_activechoicemodel:
self.fields['fk_activechoicemodel'].queryset = ActiveChoiceModel.objects.filter(active=True) | ActiveChoiceModel.objects.filter(pk=instance.fk_activechoicemodel.id)
是否有关于如何清洁和干燥10个或100个“ ActiveChoiceModels”的想法?
答案 0 :(得分:1)
我认为最好的解决方案是使用custom models.Manager来获取特殊的查询集,但是实际的工作是使用Q表达式完成的,因此,如果您不必将此查询集拉到其他位置,则可能仅使用Q表达式。没有您的代码,我没有测试过,但是从我正在运行的自定义管理器中进行了修改,加上this answer.
# models.py
from django.db import models
from django.db.models import Q
class AvailableChoiceManager(models.Manager):
"""Active choices + existing choice even if its now inactive.
"""
def get_queryset(self, pk=None):
qs = super().get_queryset() # get every possible choice
current_choice = ChoiceModel.objects.get(pk=pk):
return qs.filter((Q(pk=pk) | Q(active=True))
在模型定义中,您需要添加此管理器的实例:
#models.ActiveChoiceModel
AvailableChoices=AvailableChoiceManager()
调用方式:
qs = AvailableChoiceModel.AvailableChoices(pk=pk)
获取活动选项的列表:
choice_list = list(Choices.objects.filter(active=True).values_list('id', 'slug'))
if fk.pk not in choice_list:
choice_list.insert(0, (fk.pk, fk.slug))
将小部件的choices属性设置为choices_list:
self.fields['fk'].widget = forms.Select(
choices=choice_list,
attrs={'pk': 'lug', 'size': 7, 'style': "width:100%"})
我不确定是否有办法用不到三到四行代码来做到这一点,但我认为这不是很多。