I have a Django class based ListView listing objects. These objects can be filtered based on locations. Now I want that the location ModelChoiceFilter only lists locations which are relevant to the current user. Relevant locations are the locations he owns. How can I change the queryset?
# models.py
from django.db import models
from django.conf import settings
from rules.contrib.models import RulesModel
from django.utils.translation import gettext_lazy as _
class Location(RulesModel):
name = models.CharField(_("Name"), max_length=200)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_("Owner"),
related_name="location_owner",
on_delete=models.CASCADE,
help_text=_("Owner can view, change or delete this location."),
)
class Object(RulesModel):
name = models.CharField(_("Name"), max_length=200)
description = models.TextField(_("Description"), blank=True)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_("Owner"),
related_name="location_owner",
on_delete=models.CASCADE,
help_text=_("Owner can view, change or delete this location."),
)
location = models.ForeignKey(
Location,
verbose_name=_("Location"),
related_name="object_location",
on_delete=models.SET_NULL,
null=True,
blank=True,
)
This is my current filters.py file which shows all the locations to the user.
# filters.py
from .models import Object
import django_filters
class ObjectFilter(django_filters.FilterSet):
class Meta:
model = Object
fields = ["location", ]
This is the view which by default shows objects the user owns. It's possible to filter further by location. But the location drop-down shows too many entries.
# views.py
from django.views.generic import ListView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Object
from .filters import ObjectFilter
class ObjectListView(LoginRequiredMixin, ListView):
model = Object
paginate_by = 10
def get_queryset(self):
queryset = Object.objects.filter(owner=self.request.user)
filterset = ObjectFilter(self.request.GET, queryset=queryset)
return filterset.qs
def get_context_data(self, **kwargs):
context = super(ObjectListView, self).get_context_data(**kwargs)
filterset = ObjectFilter(self.request.GET, queryset=self.queryset)
context["filter"] = filterset
return context
My last attempt
I've tried to tweak the filters.py with adding a ModelChoiceFilter, but it ends up with an AttributeError: 'NoneType' object has no attribute 'request'.
# filters.py
from .models import Object
import django_filters
def get_location_queryset(self):
queryset = Location.objects.filter(location__owner=self.request.user)
return queryset
class ObjectFilter(django_filters.FilterSet):
location = django_filters.filters.ModelChoiceFilter(queryset=get_location_queryset)
class Meta:
model = Object
fields = ["location", ]