Cardelco
Cardelco

Reputation: 57

ListView and Form on the same view, using the form to filter the results

I'm new to Django and I've been trying to make so small app after reading the tutorial but I can't figure out what's wrong with my code.

What I'm trying to do is listing all the database entries of a model called project using a ListView with a form below it (using the same view) that the user can use to filter the entries to be shown by means of submitting data in text fields.

I managed to make that work, and it looks like this:

App

However, once the user clicks the "Filter results" button providing some filtering pattern on the textfields (let's say, filter by name = "PROJECT3", leaving the other fields blank), instead of rendering a page with the filtered data and the form below it, which is my intention, it just returns a white page.

Can anyone please explain me what is wrong with my code?

Here are the relevant parts:

forms.py

class FilterForm(forms.Form):
    pjt_name = forms.CharField(label='Name', max_length=200, widget=forms.TextInput(attrs={'size':'20'}))
    pjt_status = forms.CharField(label='Status', max_length=20, widget=forms.TextInput(attrs={'size':'20'}) )
    pjt_priority = forms.CharField(label='Priority', max_length=20, widget=forms.TextInput(attrs={'size':'20'}))
    pjt_internal_sponsor = forms.CharField(label='Int Sponsor', max_length=20, widget=forms.TextInput(attrs={'size':'20'}))
    pjt_external_sponsor = forms.CharField(label='Ext Sponsor', max_length=20, widget=forms.TextInput(attrs={'size':'20'}))

views.py

from App.models import Project
from django.views.generic import ListView
from django.shortcuts import render
from django.template import RequestContext
from App.forms import FilterForm

class ProjectListView(ListView):

    context_object_name = 'project_list'
    template_name='App/index.html'

    def get_context_data(self, **kwargs):
            context = super(ProjectListView, self).get_context_data(**kwargs)
            if 'filter_form' not in context:
                    context['filter_form'] = FilterForm()
            return context

    def get_queryset(self):
            form = FilterForm(self.request.GET)
            if form.is_valid():
                    name = form.cleaned_data['pjt_name']
                    i_sp = form.cleaned_data['pjt_internal_sponsor']
                    e_sp = form.cleaned_data['pjt_external_sponsor']
                    status = form.cleaned_data['pjt_status']
                    pri = form.cleaned_data['pjt_priority']
                    return send_filtered_results(name, i_sp, e_sp, status, pri)
            else:
                    return Project.objects.order_by('-project_creation_date')[:5]

    def send_filtered_results(name, i_sp, e_sp, status, pri):
            return  Project.objects.filter(project_name__in=name,internal_sponsor_name__in=i_sp, external_sponsor_name__in=e_sp, project_status__in=status, project_priority__in=pri).exclude(alias__isnull=True).exclude(alias__exact='')

urls.py

from django.conf.urls import patterns, url
from App.views import ProjectListView
from django.views.generic import DetailView
from App.models import Project, Task

urlpatterns = patterns('',
    url(r'^$',
            ProjectListView.as_view())

Upvotes: 1

Views: 1357

Answers (2)

The answer is in your response/status code:

After doing that I get a white page and runserver returns [23/Jan/2015 00:21:09] "POST /App/ HTTP/1.1" 405 0

You're POSTing to a view that has no POST handler. You should be getting an error saying so, but the 405 means method not allowed.

Add a post method to your CBV. Django class based views map request method to functions, so a GET is handled via CBV.get, POST via CBV.post

For demonstration purposes, add:

# essentially, mirror get behavior exactly on POST
def post(self, *args, **kwargs):
    return self.get(*args, **kwargs)

And change your form handler to pull from request.POST not request.GET.

        form = FilterForm(self.request.POST)

I suggest you start using print()s or log to start seeing what's happening. request.GET should be empty, as.. you're not using GET parameters. That data will be in request.POST.

Upvotes: 2

allcaps
allcaps

Reputation: 11228

Your code is messy and your Project.objects.filter(...) is far to aggressive. It just doesn't return any objects.

Don't use name__in=name but name__contains=name.

Upvotes: 1

Related Questions