【问题标题】:Django: How do I add data to a ModelForm subclass before validation?Django:如何在验证之前将数据添加到 ModelForm 子类?
【发布时间】:2011-12-28 02:39:49
【问题描述】:

作为 Django 中表单验证的一部分,我想检查用户上次发帖的时间。

我在stackoverflow 上查看了thisthis 问题,它们似乎解决了这个问题,并且最初使用了已接受的答案here。本质上,目前的过程是在

期间添加 request.user 对象
def form_valid(self, form):

CreateView 子类的方法。但是,这不允许在表单验证期间使用用户变量。

由于我想在验证期间访问用户变量,因为自上次发布以来的检查时间在逻辑上是验证,我需要提前将用户变量注入到表单中。

我尝试改变 get_initial() 方法:

def get_initial(self):
    initial = super(ArticleCreateView, self).get_initial()
    initial['user'] = self.request.user
    return initial

这成功地设置了初始字典中的 ['user'] 键,但这永远不会通过清理过程,它只处理 ['data'] 字典中的内容,并删除初始的任何内容。我故意将用户从表单显示中排除,但这似乎也将其从清洁过程和验证中删除。

这样做的正确方法是覆盖Form的init()方法和视图的get_initial()方法,将'user'放入initial,然后表单拉取在 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

【问题讨论】:

  • 表单是否引用了用户?如果是这样,您可以通过 self.cleaned_data['user'] 访问它
  • 表单所基于的模型有一个用户字段,但这从表单中排除,因为用户不应该能够选择用户,它应该自动设置为他们。目前我一直在 CreateView 子类的 form_valid() 部分注入用户变量。是否可以编辑传递给验证步骤的 **kwargs? (即通过 get_form_kwargs()?)

标签: python django django-forms


【解决方案1】:

您可以覆盖 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。

【讨论】:

    【解决方案2】:

    我目前解决此问题的方法是将验证保留在表单中,并将其余业务逻辑保留在视图中。因此,我做了以下事情:

    在视图中:

    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
    

    这似乎可行 - 这个解决方案有什么我没有发现的缺陷吗?

    【讨论】:

      【解决方案3】:

      我可能会覆盖表单初始化方法以获取user 参数,并将其设置在表单的某个位置。

      class MyForm()
          def __init__(self, user, *args, **kwargs):
              super(MyForm, self)__init__(*args, **kwargs)
              self.user = user
      
      
          def clean_field(...)
              if self.user ...
      

      【讨论】:

      • 感谢您的建议 - 最终结果略有不同。如果可能,我想避免在表单上设置用户,所以选择了stackoverflow.com/questions/8112859/…,它允许我将验证逻辑放在表单中,并将用户对象传递到表单的命名空间中。不确定我的解决方案是否存在我错过的固有问题 - 来自更有经验的人的意见将不胜感激!
      猜你喜欢
      • 1970-01-01
      • 2018-05-30
      • 1970-01-01
      • 2011-01-13
      • 2019-08-08
      • 2012-08-27
      • 2012-09-30
      • 2015-06-25
      • 1970-01-01
      相关资源
      最近更新 更多