Django: ListView with post() method?

neurix picture neurix · Mar 25, 2013 · Viewed 21k times · Source

I am trying to process two forms in a Django class based view. The site contains a form called form (based on GET) for narrowing the list results of the ListView and the second form status_form (based on POST).

Both forms are required since the ListView returns a list of items. Form lets the user restrict the choices and status_forms lets the user flag incorrect items via a modal form (therefore it needs to be in the same template).

My trouble is that ListView does not come with the method post, however FormView does. My class List inherits from both classes, but when I execute the class I get the error message:

Attribute Error: 'List' object has no attribute 'status_form'

How should I change my implementation to allow the second form been processed via the post method?

class List(PaginationMixin, ListView, FormMixin):
    model = ListModel
    context_object_name = 'list_objects'
    template_name = 'pages/list.html'
    paginate_by = 10 #how may items per page

    def get(self, request, *args, **kwargs):
        self.form = ListSearchForm(self.request.GET or None,)
        return super(List, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.status_form = StatusForm(self.request.POST or None)
        if self.status_form.is_valid():
            ...
        else:
            return super(List, self).post(request, *args, **kwargs)

    def get_queryset(self):
        # define the queryset
        ...
        # when done, pass to object_list
        return object_list

    def get_context_data(self, **kwargs):
        context = super(List, self).get_context_data(**kwargs)
        context.update(**kwargs)
        context['form'] = self.form
        context['status_form'] = self.status_form # Django is complaining that status_form is not existing, result since the post method is not executed
        return context

Answer

Alireza Savand picture Alireza Savand · Mar 25, 2013
# Django is complaining that status_form does not exist,
# result since the post method is not executed
context['status_form'] = self.status_form

Because you didn't define self.status_from in the first place. You have defined it in get_context_data, and it's accessible from there.

You can access you object from get_context_data in your post method;

context = self.get_context_data(**kwargs)
status_form = context['status_form']

Also consider that you can define your status_form directly in post method itself without getting it from self or get_context_data.

Redesign you views to separate each Form processing in separate Views then tight them with each-other.

Views redesign:

In nutshell, let each view to do one job. You can create a View just for processing your status_form and name it like StatusFormProcessView then on your List view return it on its post method

class List(ListView);
    def post(self, request, *args, **kwargs):
        return StatusFormView.as_view()(request) # What ever you need be pass to you form processing view

This is just an example of it, need more work to be real.

For another example; On my website index page I have a search form. when user POST or GET the search form, The processing of searching doesn't exist in my IndexView, instead I handle the whole form stuff in separate view, If form should process on GET method, I'll override get() method, If form should process on POST, I'll override post() method to send search_form data to the view that is responsible for handling of processing the search_form.

Comments response

status_form = context['status_form']

shouldn't it be

context['status_form'] = status_form

after I created it ?

You want to get status_form from context, So you need to

status_form = context['status_form']

Anyway, your form data are available on self.request.POST