来自实例的 Django ModelChoiceField 动态查询集



我有一个数据集,用户可能需要在其中编辑旧记录,但选择也需要限制为一组"活动"值。这意味着,当选择包含非活动值的实例时,需要将旧选项添加到 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 个实例不会花费任何时间。

相关内容

  • 没有找到相关文章

最新更新