Django: Search form in Class Based ListView

I think your goal is trying to filter queryset based on form submission, if so, by using GET :

class ProfileSearchView(ListView)
    template_name = '/your/template.html'
    model = Person

    def get_queryset(self):
        name = self.kwargs.get('name', '')
        object_list = self.model.objects.all()
        if name:
            object_list = object_list.filter(name__icontains=name)
        return object_list

Then all you need to do is write a get method to render template and context.

Maybe not the best approach. By using the code above, you no need define a Django form.

Here's how it works : Class based views separates its way to render template, to process form and so on. Like, get handles GET response, post handles POST response, get_queryset and get_object is self explanatory, and so on. The easy way to know what's method available, fire up a shell and type :

from django.views.generic import ListView if you want to know about ListView

and then type dir(ListView). There you can see all the method defined and go visit the source code to understand it. The get_queryset method used to get a queryset. Why not just define it like this, it works too :

class FooView(ListView):
    template_name = 'foo.html'
    queryset = Photo.objects.all()  # or anything

We can do it like above, but we can't do dynamic filtering by using that approach. By using get_queryset we can do dynamic filtering, using any data/value/information we have, it means we also can use name parameter that is sent by GET, and it's available on kwargs, or in this case, on self.kwargs["some_key"] where some_key is any parameter you specified


This is similar to @jasisz 's approach, but simpler.

class ProfileList(ListView):
    template_name = 'your_template.html'
    model = Profile

    def get_queryset(self):
        query = self.request.GET.get('q')
        if query:
            object_list = self.model.objects.filter(name__icontains=query)
        else:
            object_list = self.model.objects.none()
        return object_list

Then all you have to do on the html template is:

<form method='GET'>
  <input type='text' name='q' value='{{ request.GET.q }}'>
  <input class="button" type='submit' value="Search Profile">
</form>

Well, I think that leaving validation to form is nice idea. Maybe not worth it in this particular case, because it is very simple form - but for sure with more complicated one (and maybe yours will grow also), so I would do something like:

class ProfileList(ListView):
    model = Profile
    form_class = ProfileSearchForm
    context_object_name = 'profiles'
    template_name = 'pages/profile/list_profiles.html'
    profiles = []


    def get_queryset(self):
        form = self.form_class(self.request.GET)
        if form.is_valid():
            return Profile.objects.filter(name__icontains=form.cleaned_data['name'])
        return Profile.objects.all()