在Django Form的clean()方法中设置字段值,如果该字段没有在构造函数中传递

5 投票
3 回答
12590 浏览
提问于 2025-04-16 06:29

我需要设置一个字段的值,但这个值没有在Django表单的构造函数中传递。

我有一个模型和一个表单,像这样:

class Message(models.Model):
    created     = models.DateTimeField()
    text        = models.CharField(max_length=200, blank=True, null=True)
    active      = models.BooleanField(default=False)

class MessageForm(forms.ModelForm):
    class Meta:
        model   = Message
        exclude = ('created', 'active')

    def clean(self):
        # check if user is blocked
        if user.is_admin():
            self.cleaned_data['active'] = True
        return self.cleaned_data

期望的结果: 如果当前用户是管理员,我希望自动将消息设置为激活状态。用户不应该通过表单来传递这个参数。

实际情况: 我发现保存的消息总是标记为“假”(我可以删除条件,这样我也会看到消息没有激活)。

请帮我理解,如何在clean()方法中设置这个“激活”标志。

3 个回答

1

使用这个:

def message_form_factory(user):
    class MessageForm(forms.ModelForm):
        def clean(self):
            # check if user is blocked
            if user.is_admin():
                self.cleaned_data['active'] = True
            return self.cleaned_data
    return MessageForm

然后在你的视图中使用:

form = message_form_factory(request.user)()
form = message_form_factory(request.user)(request.POST)
3

不要在表单的 clean() 方法里做这个,应该在视图里处理。

def your_view(request):
    if request.method == 'POST':
        form = MessageForm(data=request.POST)
        if form.is_valid():
            new_message = form.save(commit=False)
            if user.is_admin():
                new_message.active = True

不过,如果你还想处理用户不是管理员的情况,并且使用同一个表单的话,可以考虑把类似的逻辑放在表单的 init() 方法里,而不是在视图里。这样做的话,可能需要从视图把用户的信息传递到表单的 init() 方法中。

5

之前的回答是可行的,但我更喜欢把表单内部的所有操作,比如显示什么和不显示什么,都封装在表单里面。我知道你提到过不想把字段值传给构造函数,但如果你不介意传用户信息的话,你的解决方案就可以用了。也就是说,你的构造函数是:

def __init__(self, user):
    self.user = user
    super(BaseForm, self).__init__()

然后在你的清理方法中,只需要把 user 改成 self.user。这样做还有一个额外的好处。假设明天你想根据用户来分配更多的字段,你就不需要在视图中添加任何东西,只需在表单中添加即可。

编辑: 当你添加一个要排除的字段时,它在清理后的数据中是不可用的。相反,你可以把它的控件设置为隐藏。

active = forms.BooleanField(widget=forms.HiddenInput)

编辑 2:如果你真的不想在表单中包含这个字段 在这种情况下,不如覆盖保存方法,而不是覆盖清理方法呢?

def save (self):
    super(BaseForm, self).save()
    if user.is_admin():
        self.instance.active=True
    super(BaseForm, self).save()

撰写回答