【问题标题】:How to modify field rendering behaviour based on state of other fields of model in django如何根据django中模型其他字段的状态修改字段渲染行为
【发布时间】:2012-02-07 09:22:36
【问题描述】:

假设我有以下模型:

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 forms api,但没有找到明显的方法。此外,在我正在开发的应用程序中,会有很多这样的领域和许多这样的模型——所以解决方案必须是无痛的。我宁愿不为每个模型创建新的 Form 类。我将主要使用 django admin 来启用编辑数据库,以及一些仅列出条目的只读视图。

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

【问题讨论】:

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


    【解决方案1】:

    这听起来像是您想在表单中而不是在对象本身中执行的操作。创建一个 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在过去的某个时间点)。

    【讨论】:

    • 好吧,我特别说我宁愿没有特定的表格。我希望能够通过允许选择非活动部队(如果它已经附加到该模型)来应对部队进入非活动状态。
    • 抱歉,我看到“没有找到明显的方法”。创建模型表单是在 Django 中执行此操作的标准方法,只需几行代码即可。否则,您可以在模型的 clean() 方法中执行此操作。我想你可以创建一个 Mixin,但这听起来比创建表单要多。
    • 好吧,我可能会结束为模型表单创建某种基类,这些基类将在 init 中执行一些逻辑,但仍将某处挂钩到 Field/Model api 将减少代码 :) .
    【解决方案2】:

    好吧,我不得不参与到 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))
    

    【讨论】:

      猜你喜欢
      • 2023-03-21
      • 2019-04-15
      • 1970-01-01
      • 1970-01-01
      • 2021-11-03
      • 2012-06-27
      • 2020-10-14
      • 2020-09-02
      • 2018-04-23
      相关资源
      最近更新 更多