Lisa Higgins
Lisa Higgins

Reputation: 45

django_filters.Filterset with context data from FilterView

I've a LearnerInstance model:

class LearnerInstance(models.Model):
    learner = models.ForeignKey(Learner, on_delete=models.CASCADE)
    aim = models.ForeignKey(Aim, on_delete=models.CASCADE)
    ...

    class Meta:
        unique_together = ("learner", "aim")

    def __int__(self):
        return self.learner

    def name(self):
        return f"{self.learner.firstname} {self.learner.surname}"

views.py

class GroupDetailView(FilterView):
    model = LearnerInstance
    template_name = "group_detail.html"
    table = LearnerGroupTable
    filterset_class = LearnerInstanceFilter

    def get_context_data(self, **kwargs):
        context = super(GroupDetailView, self).get_context_data(**kwargs)
        queryset = LearnerInstance.objects.filter(
            learner__group__short_name=self.kwargs["pk"])
        f = LearnerInstanceFilter(
            self.request.GET, queryset=queryset.filter(aim=self.request.GET.get("aim")))
        context["table"] = LearnerGroupTable(f.queryset)
        context["group"] = Group.objects.filter(short_name=self.kwargs["pk"]).values()
        return super().get_context_data(**context)

filters.py

class LearnerInstanceFilter(django_filters.FilterSet):

    class Meta:
        model = LearnerInstance
        fields = ["aim"]

Question: How do I change the filter to show only the distinct aim options returned by the queryset (all learner instances related to a selected group) within the get_context_data?

The database contains all possible aims which are offered through the filter (I know this is due to the filter being linked to the model and aim field), I want to be presented with only a list of aims that are unique to the learners within the current context.

Queryset shows unique_aims but filter is still showing all options

Upvotes: 0

Views: 44

Answers (1)

Mahrez BenHamad
Mahrez BenHamad

Reputation: 2068

updated as your question:

In my opinion, to modify the filter so that it only shows distinct aim options related to the current context, you need to override the filter's queryset and adjust your get_context_data method to achieve that:

views.py

from django_filters import rest_framework as filters

class GroupDetailView(FilterView):
    model = LearnerInstance
    template_name = "group_detail.html"
    table = LearnerGroupTable
    filterset_class = LearnerInstanceFilter

    def get_context_data(self, **kwargs):
        context = super(GroupDetailView, self).get_context_data(**kwargs)

        # Filter LearnerInstances based on the group
        queryset = LearnerInstance.objects.filter(
            learner__group__short_name=self.kwargs["pk"]
        )

        learner_instanes_filtred = LearnerInstanceFilter(
            self.request.GET,
            queryset=queryset
        )

        context["table"] = LearnerGroupTable(learner_instanes_filtred.qs)
        context["group"] = Group.objects.filter(short_name=self.kwargs["pk"]).values()
        context["filter"] = learner_instanes_filtred

        return context

and about

filters.py

class LearnerInstanceFilter(django_filters.FilterSet):
    aim = django_filters.ModelChoiceFilter(queryset=Aim.objects.none())

    class Meta:
        model = LearnerInstance
        fields = ["aim"]

    def __init__(self, *args, **kwargs):
        queryset = kwargs.pop('queryset', None)
        super().__init__(*args, **kwargs)
        
        if queryset is not None:
            unique_aims = queryset.values_list('aim', flat=True).distinct()
            self.filters['aim'].queryset = Aim.objects.filter(id__in=unique_aims)

Upvotes: 0

Related Questions