Django - 混合ListView和CreateView

时间:2012-02-18 03:12:42

标签: django listview mixins

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

我可以使用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'

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

5 个答案:

答案 0 :(得分:29)

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

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)

答案 1 :(得分:11)

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

列表视图会显示列表和网页表单,其中action网址指向创建视图
创建视图接受POST数据和

    如果出现故障,
  • 会显示包含错误消息的表单;
  • 如果成功,会重定向到列表视图

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

答案 2 :(得分:8)

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

  • ListView和CreateView是“高级”混合,聚合“较低” 等级“mixins。但这些较低级别的mixin不兼容。
  • View类直接调用render_to_response(),但在我的场景中,有2个视图类,而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))

它不干净但它有效!

答案 3 :(得分:4)

我已经自己上课来解决这个问题。我不知道它是好还是坏,但它也有效。我试图使用通用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 :(得分:0)

我遇到了这个问题并使用以下代码解决了它,@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')