Search code examples
djangodjango-filterdjango-filters

Django_filters gives an error "QuizFilter has no len()"


I have one filter:

import django_filters

from .models import Quiz


class QuizFilter(django_filters.FilterSet):
    class Meta:
        model = Quiz
        fields = ['title', 'level']

class QuizList(ListView):
    """List of quizzes + pagination"""
    model = Quiz
    template_name = 'quizapp/home.html'
    context_object_name = 'quizzes'
    paginate_by = 15

    def get_queryset(self):
        qs = self.model.objects.all()
        filtered_quizzes = QuizFilter(self.request.GET, queryset=qs)
        return filtered_quizzes

When I open the page I got this error:

enter image description here

In templates I just write {% for quiz in quizzes.qs %} and for filtering I use {{ quizzes.form.as_p }}
How can I solve the problem?


Solution

  • You here return the QuizFilter, not its filtered queryset. You need to return the .qs attribute of the QuizFilter:

    class QuizList(ListView):
        """List of quizzes + pagination"""
        model = Quiz
        template_name = 'quizapp/home.html'
        context_object_name = 'quizzes'
        paginate_by = 15
    
        def get_queryset(self):
            qs = self.model.objects.all()
            filtered_quizzes = QuizFilter(self.request.GET, queryset=qs)
            return filtered_quizzes.qs

    If you need access to the filter as well, it might be better to make use of a FilterView:

    class QuizList(ListView):
        """List of quizzes + pagination"""
        model = Quiz
        template_name = 'quizapp/home.html'
        context_object_name = 'quizzes'
        paginate_by = 15
    
        def get_queryset(self):
            qs = self.model.objects.all()
            filtered_quizzes = QuizFilter(self.request.GET, queryset=qs)
            return filtered_quizzes.qs
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context.update(
                filter=QuizFilter(self.request.GET, queryset=self.model.objects.all())
            )
            return context

    So then you can render the filter with {{ filter.form.as_p }}.