Django forms.Form 反映 属性 字段约束

Django forms.Form reflecting property field constraints

我正在实施 Django 表单 应该包含来自 modelA 的字段 'fieldA':

class ModelA(models.Model):
    fieldA =  models.CharField(max_length=8)
    ...

我的问题是:有没有办法让 Django 表单自动处理字段 A 的验证(检查 max_length)?我知道我可以使用 form.ModelFormclass 来指代 ModelA,但随后该表单将反映 ModelA 的所有字段。我想使用简单的 forms.Form.

我正在寻找类似这样的解决方案:

class formX(forms.Form):
    fieldA = forms.CharField(**modelA.fieldA.constraints)
    fieldB = ... some other fields not related to ModelA ...
    .... even more fields

也许这个问题是XY问题,但让我试试...

直接问题:从现有模型中获取字段约束

from django import forms
from django.db import models

class Foo(models.Model):
    x = models.CharField(max_length=30)
    y = models.IntegerField(null=True)

class FooForm(forms.Form):
    foo_x = forms.CharField(max_length=Foo._meta.get_field('x').max_length)

您可以通过两种方式直接访问该字段:

  1. ModelClass.field_name.field(有点乱七八糟,ModelClass.field_namedjango.db.models.query_utils.DeferredAttribute
  2. ModelClass._meta.get_field('field_name')(更好的方法,在文档的某处描述)

但是,这样您必须 a) 如果添加了字段约束则更新表单或 b) 提前指定所有属性(max_lengthmin_lengthverbose_nameblank, 等), 使 FooForm.foo_x 的声明过于冗长。

备选方案

字段子集

首先,如果您需要 Foo 个字段的子集,请使用 ModelForm 并指定它们:

class FooForm(forms.ModelForm):
    class Meta:
        fields = ('x',)

现在您有一个只有 x 字段的表单。

添加一些字段

如果您想向此表单添加字段(与其他模型无关),请这样做:

class FooForm(forms.ModelForm):
    another_field = forms.IntegerField()

    class Meta:
        fields = ('x',)

    def clean_another_field(self):
        data = self.cleaned_data['another_field'] 
        if data != 42:
            raise ValidationError('Not an answer!')  # i18n should be here
        return data

您还可以覆盖 cleansave 方法以获得其他目标,documentation 解释得很好。

混合来自不同模型的字段

如果您需要两个不同模型的字段以一种形式出现,您不需要。在这种情况下,您需要两个单独的表单,加上一些 inter-validation 此表单之外的逻辑(例如,作为视图方法,或者作为另一个 class 即 not 一个表格)。也许你需要的是inline formset,它不代表两种混合形式,但至少有一些inter-model的沟通。

我找到了一种方法来实现对反映模型字段约束的表单字段的验证。

class Foo(models.Model):
    x = models.CharField(max_length=30)
    y = models.IntegerField(null=True)

class FooForm(forms.Form):
    foo_x = forms.CharField(validators=Foo._meta.get_field('x').validators)

像这样,表单将尊重属性 xmax_length 验证器或定义的任何其他验证器。