Django:如何在验证前向ModelForm子类添加数据?

4 投票
3 回答
5896 浏览
提问于 2025-04-17 06:13

在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

这个方法看起来有效——请问我有没有忽略什么缺陷呢?

撰写回答