Django mixin 和 FormView 模板与 CBV 混淆

Django mixin and FormView template confusion with CBV

总的来说,我仍然是混入的菜鸟,所以我只是想了解这段使用 Ajax 提交表单的代码中发生了什么。我一直在搜索文档一整天,试图弄清楚会发生什么。该代码似乎有效,但我只是不完全理解为什么。我对整个过程还有很多问号所以如果有人能纠正我的想法那就太棒了

  1. AjaxableResponseMixin 扩展了 FormView 的 form_invalid() 和 form_valid() 方法以支持 Ajax 请求

    • 为什么 Ajax class 使用 super() 引用自身?
    • class 如何知道扩展 FormView 的方法?
  2. 如果请求不是Ajax它returns响应

    • 响应对象是什么do/have?它显示模板吗?它有模板的上下文吗?
  3. CreatePostView 是传入的两个父 class 的子 class(AjaxableResponseMixin,FormView)

    • 在调用 super() 时,参数中 classes 的顺序是否有一般影响,更具体地说?
    • 当 CreatePostView 调用 form_valid() 和 form_invalid() 时,是否会覆盖 Ajax class?如果不是,它改变了哪些 class 方法?
  4. 如果表单有效,则创建 post 并调用 super().form_valid() 然后重定向到成功 url 因为这就是 FormView.form_valid() 的作用

    • 同样,为什么 super() 指的是 FormView?
    • 我最好只做一个 HttpResponseRedirect 而不是使用 super()。form_valid()
  5. 如果表单无效,它会重定向到名称为 "create_post" 的 url

    • 如何重定向到创建 post 页面并将数据保留在用户尝试提交的表单中?

views.py

class AjaxableResponseMixin(object):
    """
    Mixin to add AJAX support to a form.
    Must be used with an object-based FormView (e.g. CreateView)
    """
    def form_invalid(self, form):
        response = super(AjaxableResponseMixin, self).form_invalid(form)
        if self.request.is_ajax():
            return JsonResponse(form.errors, status=400)
        else:
            return response

    def form_valid(self, form):
        response = super(AjaxableResponseMixin, self).form_valid(form)
        if self.request.is_ajax():
            data = {
                'pk': self.object.pk,
            }
            return JsonResponse(data)
        else:
            return response


class CreatePostView(AjaxableResponseMixin, FormView):
    form_class = CreatePostForm
    template_name = 'forum/create_post.html'
    success_url = reverse_lazy('home')

    def form_valid(self, form):
        user = self.request.user
        form.create_post(user_obj=user)
        messages.success(self.request, 'Your post was published')
        return super().form_valid(form)

    def form_invalid(self, form):
        messages.error(self.request, 'Your post could not be published. Please try again')
        return HttpResponseRedirect(reverse('create_post'))

非常感谢任何回答的人。

您的大部分问题都与 python 多重继承和 MRO(方法解析顺序)有关。查找一下,还有很多其他资源可以详细解释它。但是为了帮助您处理具体情况,您已按以下顺序定义了继承:

 CreatePostView --> AjaxableResponseMixin ...> FormView

这是调用 subclassed 方法的顺序。我使箭头不同,因为第一个是子 class - 父 class 关系,第二个不是(CreatePostView 是 class 的子 class FormViewAjaxableResponseMixin)

我将解释 form_valid 会发生什么:因此,如果您在 CreatePostView 上调用 form_valid() 方法,则会调用其 form_valid() 方法。这将运行该方法的所有代码。

该方法的最后一行是 return super().form_valid(form) 告诉 python 调用父级的 class 方法。使用 MRO,即 AjaxableResponseMixin.form_valid 方法。但是第一行是response = super().form_valid(...),也就是FormView.form_valid()

所以在这里,因为 super() 在开头,你有效地告诉 python 首先转到 MRO 链中的下一个。

如果请求是 ajax 请求,

AjaxableResponseMixinsuper() 响应不执行任何操作(它 returns JSON 以对象 pk 作为数据) ,但如果它不是 ajax 请求,它只是 returns FormView 响应。在这种情况下,它是到 success_url 的重定向,因为这就是 FormView 在成功的情况下所做的。可以看到here.

现在您可以用 form_invalid() 做同样的练习。事实上,它应该只是 return super().form_invalid(form)。它永远不应该重定向,因为您希望它在同一页面上 render 相同的表单(在正常情况下)或者只是报告 ajax 情况下的表单错误。

备注:

  • 如果您的方法不调用 super(),这是完全合法的,父类的 class 方法将永远不会被调用。
  • classes 的顺序和调用的顺序很重要。使用 Django CBV,您通常会 首先 调用 super() 来处理基础知识(默认行为),然后添加您自己的东西。在你的 form_valid 中,你反过来做,因为你首先要保存对象,否则 JSON 不能包含对象的 pk。实际上,如果使用不当,这个 mixin 会在那一行崩溃。
  • AjaxableResponseMixin 这样的 mixin 不包含任何 python 代码强制它是 "mixed" 和 FormView,但它必须包含,因为它调用 super().form_valid()。事实上,许多 IDE 会通过该调用警告您。没有办法告诉 python AjaxableResponseMixin 必须 FormView 混合,但它应该是文档的一部分,以便其他开发人员知道如何使用它。这同样适用于必须保存对象的警告 before calling AjaxableResponseMixin.form_valid.