Django - 在ModelForm中为字段指定默认值

5 投票
4 回答
5009 浏览
提问于 2025-04-18 06:53

在我的应用程序中,有一个 CreateView,需要把模型中的某些字段初始化为默认值,这个默认值和模型里定义的默认值不一样。

我不想让用户修改这个值,所以我把这个字段放在了 exclude 列表里。

class AForm(ModelForm):
    class Meta:
        model = AModel
        exclude = ['a_field']

class AView(CreateView):
    form_class = AForm

我的问题是:我该在哪里设置 a_field 的值呢?

我尝试在 AForm 里定义 clean 方法,像这样:

class AForm(ModelForm):
    [...]
    def clean(self):
        d = super(AForm, self).clean()
        d['a_field'] = 10
        return d

但是 a_field 的值还是被设置成了模型里定义的默认值,而不是我想要的 10。我也试过定义 clean_a_field,但这个方法根本没有被执行。

如果我把 a_fieldexclude 列表中移除,那么 cleanclean_a_field 就会生效,但表单不会通过验证,除非我在模板里渲染一个 <input name="a_field">,这并不是最好的办法。

4 个回答

0

你在模型里设置了一个默认值。根据官方的文档
比如说,a_field = models.CharField(max_length=7, default=''),这段代码的意思是:a_field这个字段最多可以有7个字符,如果没有特别指定的值,它会默认是空的。

0

我有一个方法来应对这种情况。请按照以下步骤操作:

  1. AForm 的 排除列表移除 'a_field'。

  2. 不要在 HTML 模板中 显示 'a_field'。也就是说,不要让用户通过表单在模板中更改这个值。这样可以确保普通用户不会修改这个值。

  3. 为了完全防止这种情况,重写 View 中的 get_form_kwargs 方法。 这样可以提供或重写你想要的 'a_field' 的值,并保存这个值。

例如:

class AView(CreateView):
    form_class = AForm

    def get_form_kwargs(self):
        kwargs = super(AView, self).get_form_kwargs()
        if self.request.method in {'POST', 'PUT'}:
            # Change post data to over-ride or provide value of 'a_field'
            data = self.request.POST.copy()
            data.update({
                'a_field': 'value'
            })
            kwargs['data'] = data
        return kwargs
4

可以把这个字段从表单中排除掉,然后在视图中可以在保存表单之前设置这个字段的值:

form = AForm(request.POST)
if form.is_valid():
    new_record = form.save(commit=False)
    new_record.a_field = 10
    new_record.save()

你也可以选择不使用 exclude 列表,而是通过表单定义中的 fields 属性来指定你想要包含哪些字段。具体可以查看文档的第一段,在这里

4

我找到了解决这个问题的方法,虽然我对代码还是不太满意。

a_field是模型中必填的字段,所以在模板里必须放一个<input name="a_field">。我用的窍门是把a_field设为非必填:

class AForm(ModelForm):
    a_field = Field(required=False, 
                    widget=forms.HiddenInput)
    class Meta:
        model = AModel

    def clean_a_field(self):
        return 10

这样我就可以不在模板里显示这个字段,而表单仍然可以正常验证。即使我用{{ form.as_p }}来渲染表单,widget=forms.HiddenInput也帮了我大忙。

撰写回答