【问题标题】:Django - Mixing ListView and CreateViewDjango - 混合 ListView 和 CreateView
【发布时间】:2012-03-09 10:32:11
【问题描述】:

我想创建一个带有表单的页面,每次我提交表单时,它都会在表单下方的列表中添加一个项目。

我可以使用 2 页使其工作:

  • 一页使用 mixin CreateView 添加项目
  • 一页ListView 获取列表。

但我试图将表单和列表放在同一页面上。所以我尝试用两个 mixin 创建一个类:

class FormAndListView(ListView, CreateView):
    pass

那我就用过这个类了:

FormAndListView.as_view(
    queryset=PdfFile.objects.order_by('id'),
    context_object_name='all_PDF',
    success_url = 'listview',
    form_class = UploadFileForm,
    template_name='textfrompdf/index.html',)),

但是当我尝试加载页面时,出现错误:Exception Value: 'FormAndListView' object has no attribute 'object'

Traceback:
File "C:\Program Files\Python_2.7\lib\site-packages\django\core\handlers\base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "C:\Program Files\Python_2.7\lib\site-packages\django\views\generic\base.py" in view
  47.             return self.dispatch(request, *args, **kwargs)
File "C:\Program Files\Python_2.7\lib\site-packages\django\views\generic\base.py" in dispatch
  68.         return handler(request, *args, **kwargs)
File "C:\Program Files\Python_2.7\lib\site-packages\django\views\generic\list.py" in get
  122.         return self.render_to_response(context)
File "C:\Program Files\Python_2.7\lib\site-packages\django\views\generic\base.py" in render_to_response
  94.             template = self.get_template_names(),
File "C:\Program Files\Python_2.7\lib\site-packages\django\views\generic\list.py" in get_template_names
  134.             names = super(MultipleObjectTemplateResponseMixin, self).get_template_names()
File "C:\Program Files\Python_2.7\lib\site-packages\django\views\generic\detail.py" in get_template_names
  122.         if self.object and self.template_name_field:

Exception Type: AttributeError at /PDF/
Exception Value: 'FormAndListView' object has no attribute 'object'

我不知道如何调试它。从哪里开始?

【问题讨论】:

    标签: django listview mixins


    【解决方案1】:

    不要混合列表和更新视图。
    相反,为这些任务创建两个单独的视图:

    列表视图显示列表和带有指向创建视图action URL 的网络表单。
    创建视图接受POST 数据和

    • 在失败时显示带有错误消息的表单;
    • 成功时重定向到列表视图

    我也尝试过使用基于类的视图,发现它们太复杂了。
    我认为使用旧式函数视图要容易得多。

    【讨论】:

    • 嗬,好主意!我会这样做,但是因为我是 python 和 Django 的新手,所以我很想了解它为什么不起作用或者如何找到我的错误的根源。谢谢!
    【解决方案2】:

    我找到了答案,有2个问题:

    • ListView 和 CreateView 是“高级”混合,其中聚合“较低 level” mixin。但是这些较低级别的 mixin 不能一起兼容。
    • View 类直接调用 render_to_response(),但在我的场景中,有 2 个 view 类,render_to_response() 最后只应调用一次。

    我能够通过以下步骤“解决”这个问题:

    我没有调用 ListView 和 CreateView,而是使用了较低级别的 mixins。此外,我显式调用了 BaseCreateView 和 BaseListView,我从中“提取”了表单和 object_list

    class FormAndListView(BaseCreateView, BaseListView, TemplateResponseMixin):
        def get(self, request, *args, **kwargs):
            formView = BaseCreateView.get(self, request, *args, **kwargs)
            listView = BaseListView.get(self, request, *args, **kwargs)
            formData = formView.context_data['form']
            listData = listView.context_data['object_list']
            return render_to_response('textfrompdf/index.html', {'form' : formData, 'all_PDF' : listData},
                               context_instance=RequestContext(request))
    

    它不干净,但它有效!

    【讨论】:

    • 这个视图的内容太多了,很难维护。用户jondykeman 对这个问题有一个更理智、更优雅的解决方案。
    【解决方案3】:

    我已经创建了自己的课程来解决这个问题。我不知道它是好是坏,但它也有效。我尝试使用通用 mixins 并测试了验证和分页工作。

    The code in GitHub

    class ListAppendView(MultipleObjectMixin,
        MultipleObjectTemplateResponseMixin,
        ModelFormMixin,
        ProcessFormView):
        """ A View that displays a list of objects and a form to create a new object.
        The View processes this form. """
        template_name_suffix = '_append'
        allow_empty = True
    
        def get(self, request, *args, **kwargs):
            self.object_list = self.get_queryset()
            allow_empty = self.get_allow_empty()
            if not allow_empty and len(self.object_list) == 0:
                raise Http404(_(u"Empty list and '%(class_name)s.allow_empty' is False.")
                              % {'class_name': self.__class__.__name__})
            self.object = None
            form_class = self.get_form_class()
            form = self.get_form(form_class)
            context = self.get_context_data(object_list=self.object_list, form=form)
            return self.render_to_response(context)
    
        def post(self, request, *args, **kwargs):
            self.object = None
            return super(ListAppendView, self).post(request, *args, **kwargs)
    
        def form_invalid(self, form):
            self.object_list = self.get_queryset()
            return self.render_to_response(self.get_context_data(object_list=self.object_list, form=form))
    

    如果您尝试并发现任何错误,请在此处或在 GitHub 中告诉我。

    【讨论】:

      【解决方案4】:

      我使用了很多涉及表单和对象列表的视图。我没有尝试混合事物,而是将查询集添加到上下文数据中,如下所示。

      class UploadFileView(CreateView):
          form_class = UploadFileForm
          success_url = 'listview'
          template_name = 'textfrompdf/index.html'
      
          def get_context_data(self, **kwargs):
              kwargs['object_list'] = PdfFile.objects.order_by('id')
              return super(UploadFileView, self).get_context_data(**kwargs)
      

      【讨论】:

      • 这可能非常优雅,但有更多解释会有所帮助。
      • 用这种用法对列表进行分页是否有问题?
      • 但这不会分页
      【解决方案5】:

      我遇到了这个问题并使用以下代码解决了它,@jondykeman 的答案没有分页和其他基类实用程序。提出的其他方法比以下方法稍微复杂一些:

      class ObjectCreateView(LoginRequiredMixin, MultipleObjectMixin, View):
      
         queryset = Wallet.objects.all()
      
         def get(self, request):
             self.object_list = super(ObjectCreateView, self).get_queryset().filter(user=request.user)
             allow_empty = super(ObjectCreateView, self).get_allow_empty()
      
             if not allow_empty:
                 if super(ObjectCreateView, 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 = not self.object_list
                 if is_empty:
                     raise Http404()
             context = super(ObjectCreateView, self).get_context_data()
             form = CreateObjectForm()
             context['form'] = form
             return render(request, 'objects/object-list.html', context=context)
      
        def post(self, request):
             form = CreateWalletForm(request.POST)
             if form.is_valid():
              Object.objects.create(name=form.cleaned_data['name'], user=request.user)
                 messages.success(request, 'Object is created')
             else:
                 messages.error(request, utility.get_form_errors_as_string(form))
             return redirect('objects:create')
      

      【讨论】:

        猜你喜欢
        • 2023-03-04
        • 2013-10-20
        • 2013-05-19
        • 2014-01-14
        • 1970-01-01
        • 2016-11-30
        • 2015-08-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多