Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - Mixing ListView and CreateView

I'm want to create one page with a form, and every time I submit the form it adds an item to the list below the form.

I can make it work using 2 pages:

  • one page using the mixin CreateView to add items
  • one page ListView to have the list.

But I'm trying to have the form and the list on the same page. So I tried to create a class with both mixin:

class FormAndListView(ListView, CreateView):
    pass

Then I've used this class:

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',)),

But when I try to load the page, I get the error: 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'

I've no idea how to debug that. Where to start?

like image 691
Nico Avatar asked Feb 18 '12 03:02

Nico


3 Answers

Do not mix list and update views.
Instead, create two separate views for these tasks:

List view displays the list and a web form with action URL pointing to the create view.
Create view accepts POST data and

  • displays form with error message in case of failure;
  • redirects to the list view in case of success.

Also I've tried to use class-based views and found that they are too complex.
I think it is much easier to use old-style function views.

like image 44
Stack Exchange User Avatar answered Oct 14 '22 15:10

Stack Exchange User


I use a lot of views that involve a form and a list of objects. Rather than trying to mixin things I just add the queryset into the context data as below.

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)
like image 98
jondykeman Avatar answered Oct 14 '22 14:10

jondykeman


I found the answer, there is 2 problems:

  • ListView and CreateView are "high level" mixin which aggregate "lower level" mixins. But these lower level mixins are not compatible together.
  • The View class calls directly the render_to_response(), but in my scenario, there is 2 view class and render_to_response() should only be called once at the end.

I was able "solve" this issue using the following steps:

Instead of calling ListView and CreateView, I used lower level mixins. Moreover I called explicitly BaseCreateView and BaseListView from which I "extracted" the form and 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))

It's not clean but it works!

like image 9
Nico Avatar answered Oct 14 '22 14:10

Nico