[Answer]-Django form submit not working

0👍

This needs to be done in the form_valid() method, not the get_context_data method. get_context_data is just used to provide extra data (aka context) to the template during the request.

1👍

As others have said you have issues with the fact all your code is in get_context_data. In all actuality you don’t even need to use get_context_data to accomplish what you are trying to do.

From what I can see you are trying to get comments on the page. Then submit a form back to the page and get a filtered out set of comments returned, and rendered. Here is a view solution that better does what you want except using generic class based views more fully.

class FilterCommentsUIView(FormMixin, ListView):
    template_name = 'allcomments.html'
    form_class = CommentFilterForm
    paginate_by = 20
    model = Item
    context_object_name = 'comments'
    qs_kwargs = {}

    def post(self, request, *args, **kwargs):
        """
        Handles POST requests, instantiating a form instance with the passed
        POST variables and then checked for validity.
        """
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def get_queryset(self):
        qs = super(FilterCommentsUIView, self).get_queryset()
        if self.qs_kwargs:
            return qs.filter(**self.qs_kwargs)
        return qs

    def form_valid(self, form):
        parenttype = form.cleaned_data['pchoice']
        users  = form.cleaned_data('users')
        tags   = form.cleaned_data('tags')
        fdate  = form.cleaned_data('fdate')
        tdate  = form.cleaned_data('tdate')
        typeuser = form.cleaned_data('typeuser')
        query  = form.cleaned_data('query')
        userid = User.objects.get(username ='pavan')

        # put logic here on what to expand into a filter on orm
        self.qs_kwargs['user'] = userid.id

        self.render_to_response(self.get_context_data())

I haven’t run this code, but this is how it should work.

This uses the FormMixin to give us form functionality along with the ListView with your Item class. This takes care of querying for your objects and paginating them, along with a basic get method.

Also the ListView inherits from TemplateResponseMixin which has your template code so you don’t need to inherit from TemplateView so in the code above I removed that.

Based on the very nature of the base View class which ListView uses the dispatch method detects whether you are doing a GET, POST, PUT, DELETE, etc… As such it calls the appropriate method on the view. In this case since you are doing a POST it will call the post method in the view. The FormView‘s implementation of post is this:

def post(self, request, *args, **kwargs):
    """
    Handles POST requests, instantiating a form instance with the passed
    POST variables and then checked for validity.
    """
    form_class = self.get_form_class()
    form = self.get_form(form_class)
    if form.is_valid():
        return self.form_valid(form)
    else:
        return self.form_invalid(form)

Since we aren’t using FormView, but are using FormMixin We need to include it.

So all it does is get the form class you set in self.form_class instantiates it, then checks if it is valid. If so calls the form_valid method. Thus we overrode the form_valid method above. Since it passes in the form with it and it has cleaned all the data we can use the normal django form of form.cleaned_data. This helps us with security so we should use that to get back information.

In the last part of the form_valid method we are returning render_to_response. Normally this just redirects to self.success_url, but we want to render the page so we just do a render_to_response and pass it in our context data. We call self.get_context_data() because that is what builds all the data for paginating our comments that we need.

Now comes a bit of the magic. if you notice there is self.qs_kwargs. This is something that is not normally in GCBV’s, but something I added for this implementation. Here is where you would put logic to build a dictionary of filters to run in your orm call in get_queryset. We pack it into the dictionary, because in the get_queryset method above we unpack it all, if needed, to do our filtering.

So if you have:

qs_kwargs = {'user': user.id, 'created__gt': somedate}

And you do:

qs.filter(**qs_kwargs) or Item.objects.filter(**qs_kwargs)

That is roughly the same as doing:

qs.filter(user=user.id, created__gt=somedate) or Item.objects.filter(user=user.id, created__gt=somedate)

Finally, if you pay attention to the get_queryset method you notice it returns back all results, like you want, unless qs_kwargs is populated which happens from the form_valid method. So it takes in to account both GET and POST on the page.

Also to keep things simple your html should look something like this:

<html>
    <head></head>
    <body>
        <div>
            {% for comment in comments %}
            {{ comment }}
            {% endfor %}
             <ul class="pagination">
                {% if page_obj.has_previous() %}
                <li><a href="?page={{ page_obj.previous_page_number }}">Previous</a></li>
                {% endif %}
                {% for pg in paginator.page_range %}
                {% if page_obj.number == pg %}
                <li class="active"><a href="?page={{ pg }}">{{ pg }}</a></li>
                {% else %}
                <li><a href="?page={{ pg }}">{{ pg }}</a></li>
                {% endif %}
                {% endfor %}
                {% if page_obj.has_next() %}
                <li><a href="?page={{ page_obj.next_page_number() }}">Next</a></li>
                {% endif %}
            </ul>
        </div>
        <div>
            <form action="" method="POST">
                {% csrf_token %}
                {{ form.as_p }}
                <input type="submit" value="submit" />
            </form>
        </div>
    </body>
</html>

Hope that helps.

Leave a comment