django 在 class 基于视图(ListView)中呈现和验证表单集

django render and validate formset in class based-view (ListView)

我有以下基于 class 的视图,我想使用它来呈现表单集并在通过 post 方法提交时对其进行验证:

表单集呈现完美。当我提交表单时,我可以阅读表单集并检查它是否有错误。在这个 class 的 post 方法中 -> errors = backorder_formset.errors

如果我在表单集中发现任何错误,我想呈现视图,但这次使用我从 POST 读取的表单集实例。 当我在 class 的 post 方法中调用 ctx = self.get_context_data() 表单时,调用 super(MissingProductsListView, self).get_context_data(*args, **kwargs) 会引发以下错误: 'MissingProductsListView' object has no attribute 'object_list'

似乎Listview的superclass执行了这个调用:queryset = kwargs.pop('object_list', self.object_list)

我的问题是为什么我 运行 会出现这个错误?以及如何在 posted 之后呈现带有错误消息的此表单集以将其显示在模板中?我正在使用 Django 1.9.9

class MissingProductsListView(generic.ListView):
    template_name = 'dashboard/purchaseorder/missing_products.html'
    context_object_name = 'backorders'
    model = BackOrder

    def post(self, request, *args, **kwargs):
        backorder_formset = BackOrderFormset(request.POST)
        errors = backorder_formset.errors

        if backorder_formset.is_valid():
            # <process form cleaned data>
            return HttpResponseRedirect('/success/')
        else:
            ctx = self.get_context_data()
            return self.render_to_response(ctx)


    def accumulate_identical_products_from_backorders(self, back_order_list):
        ... some code
        return sorted_accumulated_dict.values()

    def get_context_data(self, *args, **kwargs):
        ctx = super(MissingProductsListView, self).get_context_data(*args, **kwargs)
        ctx['title'] = _("Missing Products")
        if self.request.POST:
            ctx['back_order_formset'] = BackOrderFormset(self.request.POST)
        else:
            accumulated_backorders_per_product = self.accumulate_identical_products_from_backorders(BackOrder.objects.all())

            back_orders = BackOrderFormset(initial=[{'product_id': backorder_dict['product_id'],
                                                     'product': backorder_dict['title'],
                                                     'quantity': backorder_dict['quantity']} for backorder_dict in
                                                    accumulated_backorders_per_product])
            ctx['back_order_formset'] = back_orders
        return ctx

    def get_queryset(self):
      .. some code
        return backorder_list

看这里:

class BaseListView(MultipleObjectMixin, View):
    """
    A base view for displaying a list of objects.
    """
    def get(self, request, *args, **kwargs):
        self.object_list = self.get_queryset()
        allow_empty = self.get_allow_empty()

        if not allow_empty:
            # When pagination is enabled and object_list is a queryset,
            # it's better to do a cheap query than to load the unpaginated
            # queryset in memory.
            if self.get_paginate_by(self.object_list) is not None and hasattr(self.object_list, 'exists'):
                is_empty = not self.object_list.exists()
            else:
                is_empty = len(self.object_list) == 0
            if is_empty:
                raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.") % {
                    'class_name': self.__class__.__name__,
                })
        context = self.get_context_data()
        return self.render_to_response(context)

基本上 - 您在 POST 处理程序中错过了这一部分:

self.object_list = self.get_queryset()

老实说——我不太确定将 post 添加到 Django 中的通用 ListView 是否是个好主意。它看起来更像 FormView - 但我在这里可能是错的。