如何根据django中其他模型字段的状态修改字段渲染行为

时间:2012-01-10 23:39:55

标签: python django django-models model django-forms

我们假设我有以下模型:

class ScoutBook(models.Model):
       troop = models.ForeignKey('Dictionary', limit_choices_to={'type' : 'Troop'},  related_name='+', blank=True, null=True)

class Dictionary(models.Model): 
     name = models.CharField(max_length=CHAR_FIELD_MAX_LEN, verbose_name="Nazwa")
     active = models.BooleanField(verbose_name="Aktywny")
     type = models.CharField(max_length=CHAR_FIELD_MAX_LEN, choices=DICTIONARY_CHOICES)

我想实现以下逻辑:

创建ScoutBook时,允许用户只选择活动部队,编辑时允许选择活动部队或允许用户保持值不变(即使部队处于非活动状态)。如果我使用limit_choices_to = {..., 'active' = True} django admin中的组合框中没有非活动队伍。

所以要明确:让我们假设这个系统中有四个部队:Troop1Troop2InactiveTroopInactiveTroop2。在模型创建方面,我希望用户能够选择Troop1Troop2。如果模型的部队字段设置为InactiveTroop2,我希望用户能够在InactiveTroop2Troop1Troop2之间进行选择。

我正在看django表格api,我没有找到明显的办法。而且,在我正在开发的应用程序中,将会有许多这样的领域和许多这样的模型---因此解决方案必须是无痛的。我宁愿不为每个模型创建新的Form类。我将主要使用django admin来启用编辑数据库,以及一些只读列表条目的只读视图。

理想情况下,我想在一些自定义字段中封装此功能---但是字段可以在验证和保存阶段访问模型实例---所以当我生成formfield时我无法访问它。

2 个答案:

答案 0 :(得分:0)

这听起来像你想要在表单中做的事情,而不是在对象本身。创建一个ModelForm并覆盖ModelChoiceField,如下所示:

from django import forms

class ScoutBookForm(forms.ModelForm):
    troop = forms.ModelChoiceField(queryset=Troop.objects.filter(active=True))
    class Meta:
        model = ScoutBook

您还可以override the clean method of ScoutBook确保无法使用非活动队伍保存它,但这可能会产生一些意想不到的后果(例如,如果部队拥有,您将无法在管理员中更新ScoutBook在过去的某个时刻变得不活跃。)

答案 1 :(得分:0)

好吧,我不得不挂钩进入ModelForm创建。附加表单检查它的字段,如果满足特定条件,它将替换模型字段查询集。

    class DictionayModelForm(ModelForm):
        def __init__(self, *largs, **kwargs):
            super(DictionayModelForm, self).__init__(*largs, **kwargs)
            if self.instance and self.instance.pk is not None:
                for f in self.instance._meta.fields:
                    if isinstance(f, models.ForeignKey) and issubclass(f.rel.to, Dictionary):
                        model_field = self.fields[f.name]
                        value = getattr(self.instance, f.name, None)
                        if value and value not in model_field.choices:
                            model_field.queryset = Dictionary.objects.filter(Q(**f.rel.limit_choices_to) | Q(id = value.id))