How do I create a Django ListView with FormMixin?
I have a working ListView with template. I want to filter the list based on the contents of a form, something like:
class SampleListView(FormMixin, ListView):
model = Sample
paginate_by = 15
form_class = LookupForm
def get_queryset(self):
samples = Sample.objects.all()
# filter based on validated form contents
form = self.get_form()
if form.is_valid():
samples = samples.filter(some_property__gte=form.cleaned_data['sample_number'])
return samples
class LookupForm(forms.Form):
sample_number = IntegerField(widget=NumberInput)
The template shows the form as:
<form action="" method='get'>
{% csrf_token %}
{{ form.as_p }}
<input type='submit' value='Query samples'>
</form>
This renders the page with my list and form, but the form always seems to be invalid. How can I integrate the validated form with my ListView? Is this the Avoid anything more complex? That is, should I just not be trying to put the FormMixin and ListView together?
FormMixin looks for data in request.POST by default. Since you are using a GET form for filtering, the form is never actually bound to your data, so is_valid() fails (or the form remains empty).
Override get_form_kwargs to inject the GET data when parameters are present:
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
# Bind the form to GET data if parameters are present
if self.request.GET:
kwargs['data'] = self.request.GET
return kwargs
This fixes your get_queryset logic and ensures the search values persist in the input fields after the page reloads.
To integrate FormMixin with ListView in Django, follow these steps:
Inherit from
ListViewandFormMixin:from django.views.generic import ListView from django.views.generic.edit import FormMixin class SampleListView(FormMixin, ListView): model = Sample paginate_by = 15 form_class = LookupFormOverride
get_form_kwargsto bind form to GET data:def get_form_kwargs(self): kwargs = super().get_form_kwargs() if self.request.GET: kwargs['data'] = self.request.GET return kwargsModify
get_querysetto filter based on form data:def get_queryset(self): queryset = super().get_queryset() form = self.get_form() if form.is_valid(): queryset = queryset.filter(some_property__gte=form.cleaned_data['sample_number']) return queryset
This setup ensures your form data is correctly bound and used to filter the list view results.
For more details, refer to the Django documentation on using mixins with class-based views.