在Django Form的clean()方法中设置字段值,如果该字段没有在构造函数中传递
我需要设置一个字段的值,但这个值没有在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()