Search code examples
djangodjango-filterdjango-generic-views

Using django-filter with class DetailView


I want to make a dynamic filtering form with Django and django-filter like stackoverflow filter enter image description here

and i want to use this filter on a template that render by DetailView , now the problem is i searched alot and i didn't found example of how to make this happen

in my template i list all 'courses' that related to 'materials' class and i want to make a form on the same template so i can filter this list

my template

{% for course in material_detail.courses_set.all %}
<div class="course">
    <h5>{{ course.course_name }}</h5>
    <p>{{ course.course_description }} </p>            
</div>
<hr/>
{% endfor %}

I have two models 'Materials' and 'Courses' my models.py

class Materials(models.Model):
    materials_name          = models.CharField(max_length=200)
    materials_description   = models.CharField(max_length=200, null=True)
    slug_material           = models.SlugField(blank=True, unique=True)


class Courses(models.Model):
    course_name             = models.CharField(max_length=200)
    course_description      = models.CharField(max_length=300, null=True)
    material                = models.ForeignKey(Materials, on_delete = models.CASCADE)

and i have one Class DetailView my views.py

class MaterialsDetailView(DetailView):
    model               = Materials
    template_name       = 'tuts/material.html'
    context_object_name = 'material_detail'

I have made a filters.py file and make this code on it , but i don't know how to link this with my Class DetailView

import django_filters

from .models import Materials

class CourseFilter(django_filters.FilterSet):

class Meta:
    model = Materials
    fields = ['courses__course_name', 'courses__course_description']

Note: there are more code on my models and template i remove it to make the code very simple


Solution

  • You are just displaying the course list related to the material. So you can filter related courses with f = CourseFilter(self.request.GET, queryset=Courses.objects.filter(material=material_pk)). Notice I m using the CourseFilter instead of MaterialFilter

    views.py

    class MaterialsDetailView(DetailView):
        model = Materials
        template_name = 'tuts/material.html'
        context_object_name = 'material_detail'
    
        def get_context_data(self, **kwargs):
            context_data = super(MaterialsDetailView, self).get_context_data()
            material_pk = self.kwargs.get('pk', None)
            f = CourseFilter(self.request.GET, queryset=Courses.objects.filter(material=material_pk))
            context_data['filter'] = f
            return context_data
    

    filters.py

    class CourseFilter(django_filters.FilterSet):
        class Meta:
            model = Courses
            fields = []
        course_name = django_filters.CharFilter(field_name="course_name", lookup_expr="icontains")
        course_description = django_filters.CharFilter(field_name="course_description", lookup_expr="icontains")
    

    In your template, you can access all your filtered queryset in filter.qs and the corresponding form in filter.form

    tuts/material.html

    <form method="GET">
        {{ filter.form.as_p }}
        <input type="submit" />
    </form>
    {% for course in filter.qs %}
    <div class="course">
        <h5>{{ course.course_name }}</h5>
        <p>{{ course.course_description }} </p>
    </div>
    <hr/>
    {% endfor %}