Django CreateView:在验证之前设置用户

Flo*_*etz 2 django django-validation django-generic-views django-class-based-views

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

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 },
                )
Run Code Online (Sandbox Code Playgroud)

我想创建一个Form和一个CreateView,用户可以使用它们创建对象。用户创建此类对象时,应将用户用作“创建者”字段值的值。

当前看起来像这样:

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)
Run Code Online (Sandbox Code Playgroud)

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

在基于类的通用视图CreateView中访问request.user以便在Django中设置FK字段

不幸的是,它不起作用:“视图”仅允许我创建以下划线开头的Symbol,而在此情况下应相反。但是,当我创建符号时,无论如何都正确设置了创建者字段。

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

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

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

Ala*_*air 5

您可以instance.creatorget_form_kwargs方法中进行设置。

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
Run Code Online (Sandbox Code Playgroud)

检查if kwargs['instance'] is None手段,该代码可以使用两种CreateViewUpdateView