我有一个数据集,用户可能需要在其中编辑旧记录,但选择也需要限制为一组"活动"值。这意味着,当选择包含非活动值的实例时,需要将旧选项添加到 ModelChoiceField 的查询集中。
在我看来,执行此操作的理想方法是对ModelChoiceField进行子类化,但是我似乎找不到实例数据在ModelChoiceField中的插入点。 我能够通过在 forms.py 中设置查询集来使其工作,但我有大量需要的字段,并且真的希望有一个更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)
这可以通过以下 forms.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"做这个清洁和干燥的任何想法?
选项 1
我认为最好的解决方案是自定义模型。用于获取特殊查询集的管理器。但是,实际工作是通过 Q 对象完成的,因此,如果您不必在其他任何地方拉取此查询集,则可能只能使用 Q 对象。没有你的代码我还没有测试过这个,但它是从我正在运行的自定义管理器修改的,加上这个答案。
# models.py
from django.db import models
from django.db.models import Q
class AvailableChoiceManager(models.Manager):
"""Active choices + existing choice even if it's 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)
选项 2.
获取活动选项的列表:
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))
将小组件的选择属性设置为 choice_list
:
self.fields['fk'].widget = forms.Select(
choices=choice_list,
attrs={'pk': 'lug', 'size': 7, 'style': "width:100%"})
我认为你需要的是limit_choices_to
例如:
fk_activechoicemodel = models.ForeignKey('mydb.ActiveChoiceModel',limit_choices_to={'active': True}, on_delete=models.CASCADE)
此条件将应用于"选择"字段或表单中的其他字段。 因此,仅当其active
字段的值为 True
时,它才会从模型ActiveChoiceModel
中获取值。您也可以添加其他条件。
另一种方法是使用 django-autocomplete。 您可以在视图中添加条件,就像筛选查询集一样,它将动态加载,以便 1000 个实例不会花费任何时间。