Django:如何在验证前向ModelForm子类添加数据?
在Django的表单验证中,我想检查用户最后一次发布内容的时间。
我查看了这个和这个问题,它们似乎都在讨论这个问题。最开始我使用了这里的接受答案。现在的过程是,在
def form_valid(self, form):
CreateView子类的方法中添加request.user对象。不过,这样做并不能在表单验证时使用用户变量。
因为我想在验证时访问用户变量,检查上次发布的时间逻辑上属于验证的一部分,所以我需要更早地将用户变量注入到表单中。
我尝试修改get_initial()方法:
def get_initial(self):
initial = super(ArticleCreateView, self).get_initial()
initial['user'] = self.request.user
return initial
这成功地在初始字典中设置了['user']这个键,但这个值从来没有经过清理过程,因为清理过程只处理['data']字典中的内容,并且会移除初始字典中的任何东西。我故意将用户排除在表单显示之外,但这似乎也使它在清理过程和验证中被移除。
这样做的正确方法是重写init()方法和视图的get_initial()方法,将'user'放入初始字典,然后在init()中让表单从初始字典中提取额外信息吗?
我想把request.user传递给表单,然后我可以在表单的clean()方法中访问它,以进行额外的检查,这实际上就是验证。
def clean(self):
super(ArticleForm, self).clean()
**check whether user has posted recently, if so, raise ValidationError**
return self.cleaned_data
J
3 个回答
0
我可能会重写表单的初始化方法,让它接受一个user
参数,然后把这个参数存储在表单的某个地方。
class MyForm()
def __init__(self, user, *args, **kwargs):
super(MyForm, self)__init__(*args, **kwargs)
self.user = user
def clean_field(...)
if self.user ...
等等
5
你可以重写 CreateView 里的 get_form_kwargs 方法(在你的例子中是 ArticleCreateView),这样就可以把用户信息传递给表单。
def get_form_kwargs(self):
kwargs = super(ArticleCreateView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
接下来,重写你表单里的 init 方法。
...
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user")
现在你可以在 clean 方法中使用 self.user 了。
4
我现在解决这个问题的方法是把验证放在表单里,而把其他的业务逻辑放在视图中。因此,我做了以下几件事:
在视图中:
def get_initial(self):
initial = super(MyCreateView, self).get_initial()
initial['user'] = self.request.user
return initial
在表单中:
def __init__(self, *args, **kwargs):
self.user = kwargs['initial']['user']
super(MyObjectForm, self).__init__(self, *args, **kwargs)
def clean(self):
# Clean all the submitted data
super(MyObjectForm, self).clean()
# Validate that the user submitted > n time ago
profile = self.user.get_profile()
if datetime.now() - profile.lastpost < timedelta(hours=1)
raise forms.ValidationError("Need to wait longer than n=1 hours")
else:
self.cleaned_data['user'] = self.user
return self.cleaned_data
这个方法看起来有效——请问我有没有忽略什么缺陷呢?