【问题标题】:Django CreateView: set user before validationDjango CreateView:在验证之前设置用户
【发布时间】:2018-02-08 05:46:12
【问题描述】:

我有一个模型对其名称字段使用不同的验证,具体取决于对象是由用户创建还是由系统创建。

class Symbol(models.Model):
    name = models.CharField(_('name'), unique=True, max_length=64)
    creator = models.ForeignKey('User', null=True, on_delete=models.CASCADE)
    def is_system_internal(self):
        """
        whether or not this Symbol belongs to the system rather than having been created by a user
        """
        return (self.creator is None)
    def clean(self):
        """
        ensure that the Symbol's name is valid
        """
        if self.is_system_internal():
            if not re.match("^_[a-zA-Z0-9\-_]+$", self.name):
                raise ValidationError(
                    _("for system-internal symbols, the name must consist of letters, numbers, dashes (-) and underscores (_) and must begin with an underscore."),
                    params = { 'value' : self.name },
                )
        else:
            if not re.match("^[a-zA-Z][a-zA-Z0-9\-_]*$", self.name):
                raise ValidationError(
                    _("the symbol name must consist of letters, numbers, dashes (-) and underscores (_) and must begin with a letter."),
                    params = { 'value' : self.name },
                )

我想创建一个表单和一个 CreateView,用户可以使用它们创建对象。当用户创建这样一个对象时,用户应该被用作'creator'字段的值。

目前看起来是这样的:

class SymbolCreateForm(forms.ModelForm):
    name = forms.CharField(max_length=Symbol._meta.get_field('name').max_length, required=True)
    class Meta:
        model = Symbol
        fields = ('name',)

class SymbolCreateView(LoginRequiredMixin, generic.CreateView):
    form_class = SymbolCreateForm
    template_name = 'main/symbol_create.html'
    def form_valid(self, form):
        # set the creator of the instance to the currently logged in user
        form.instance.creator = self.request.user
        return super(SymbolCreateView, self).form_valid(form)

我这样写是因为这就是这个相关问题的答案:

Accessing request.user in class based generic view CreateView in order to set FK field in Django

不幸的是,它不起作用:视图只允许我创建以下划线开头的符号,它应该做相反的事情。但是,当我创建符号时,无论如何都会正确设置创建者字段。

我认为问题在于创建者字段只有在 clean() 方法已经运行之后才被设置。

如何在调用 clean() 方法之前设置创建者字段?

或者,有没有更好的方法来做我想做的事情? 在我看来,应该有一种更有效的方法来自动化我对名称字段有两个不同验证器的逻辑,其中的选择取决于创建者字段。

【问题讨论】:

    标签: django django-class-based-views django-generic-views django-validation


    【解决方案1】:

    就我而言,我希望请求用户参与验证过程。 提出的解决方案here 更合适。它建议使用form_valid如下

    def form_valid(self, form):
      form.instance.author = self.request.user
      # ... do some validation here about the user for example
      if passed_validation:
        return super().form_valid(form)
    
      form.add_error(None, ValidationError({"author": "invalid author because ..."}))
      return super().form_invalid(form)
    

    【讨论】:

      【解决方案2】:

      您可以在get_form_kwargs 方法中设置instance.creator

      class SymbolCreateView(LoginRequiredMixin, generic.CreateView):
          form_class = SymbolCreateForm
      
          def get_form_kwargs(self):
              kwargs = super(SymbolCreateView, self).get_form_kwargs()
              if kwargs['instance'] is None:
                  kwargs['instance'] = Symbol()
              kwargs['instance'].creator = self.request.user
              return kwargs
      

      检查if kwargs['instance'] is None 意味着代码同时适用于CreateViewUpdateView

      【讨论】:

      • 我收到 TypeError:“** 后的 ModelFormMetaclass 对象参数必须是映射,而不是 NoneType”
      • 记得回kwargs
      猜你喜欢
      • 1970-01-01
      • 2015-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-03
      • 2013-10-21
      • 1970-01-01
      相关资源
      最近更新 更多