实例

时间:2018-08-06 22:53:25

标签: python django

我有一个数据集,用户可能需要编辑旧记录,但选择也必须限于一组“活动”值。这意味着,当选择包含非活动值的实例时,需要将旧选项添加到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”的想法?

1 个答案:

答案 0 :(得分:1)

选项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)

选项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))

将小部件的choices属性设置为choices_list:

self.fields['fk'].widget = forms.Select(
            choices=choice_list,
            attrs={'pk': 'lug', 'size': 7, 'style': "width:100%"})

我不确定是否有办法用不到三到四行代码来做到这一点,但我认为这不是很多。