Django-filter:具有基于 request.user 的查询集的 ModelChoiceFilter
Django-filter: ModelChoiceFilter with request.user based queryset
我有一个基于 Django class 的 ListView 列表对象。可以根据位置过滤这些对象。现在我希望位置 ModelChoiceFilter 只列出与当前用户相关的位置。相关位置是他拥有的位置。如何更改查询集?
# 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,
)
这是我当前的 filters.py 文件,它向用户显示 所有 位置。
# filters.py
from .models import Object
import django_filters
class ObjectFilter(django_filters.FilterSet):
class Meta:
model = Object
fields = ["location", ]
这是默认显示用户拥有的对象的视图。可以按位置进一步过滤。但是位置下拉列表显示的条目太多。
# 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
我最后一次尝试
我试图通过添加 ModelChoiceFilter 来调整 filters.py,但它以 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", ]
这段代码的问题:
def get_location_queryset(self):
queryset = Location.objects.filter(location__owner=self.request.user)
return queryset
是基于函数的视图,您添加了 self
作为参数,并尝试访问 self
的上下文中不存在的 request
,因为 [=13] =] 值对我们来说是未定义的
我将如何通过创建基于 class 的位置过滤视图来根据用户过滤掉位置
class LocationView(ListView):
def get_queryset(self):
return Location.objects.filter(owner=self.request.user)
在filters.py中:
class ObjectFilter(django_filters.FilterSet):
location = django_filters.filters.ModelChoiceFilter(queryset=LocationView.as_view())
class Meta:
model = Object
fields = ["location", ]
我相信这里有几个不同的问题在起作用。首先,根据 django-filter docs,当可调用对象传递给 ModelChoiceFilter
时,它将以 Filterset.request
作为其唯一参数进行调用。所以你的 filters.py
需要像这样重写:
# filters.py
from .models import Object
import django_filters
def get_location_queryset(request): # updated from `self` to `request`
queryset = Location.objects.filter(location__owner=request.user)
return queryset
class ObjectFilter(django_filters.FilterSet):
location = django_filters.filters.ModelChoiceFilter(queryset=get_location_queryset)
class Meta:
model = Object
fields = ["location", ]
这是拼图的一半。我相信另一个问题在你看来。 django-filter
有视图 类 处理传递给过滤器集的请求,但这不会使用 Django 的通用 ListView
自动发生。尝试将您的视图代码更新为如下内容:
# views.py
from django_filters.views import FilterView
class ObjectListView(LoginRequiredMixin, FilterView): # FilterView instead of ListView
model = Object
filterset_class = ObjectFilter
这应该会为您传递请求。
另请注意,根据上面链接的 django-filter 文档,您的查询集应处理 request
为 None
的情况。我个人从未在我的项目中看到过这种情况,仅供参考。
作为替代方案,如果您不想使用 FilterView
,我相信您示例中的代码几乎就在那里:
# views.py alternative
class ObjectListView(LoginRequiredMixin, ListView):
model = Object
paginate_by = 10
def get_queryset(self):
filterset = ObjectFilter(self.request)
return filterset.qs
我认为这也适用于我上面指定的 filters.py
。
我有一个基于 Django class 的 ListView 列表对象。可以根据位置过滤这些对象。现在我希望位置 ModelChoiceFilter 只列出与当前用户相关的位置。相关位置是他拥有的位置。如何更改查询集?
# 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,
)
这是我当前的 filters.py 文件,它向用户显示 所有 位置。
# filters.py
from .models import Object
import django_filters
class ObjectFilter(django_filters.FilterSet):
class Meta:
model = Object
fields = ["location", ]
这是默认显示用户拥有的对象的视图。可以按位置进一步过滤。但是位置下拉列表显示的条目太多。
# 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
我最后一次尝试
我试图通过添加 ModelChoiceFilter 来调整 filters.py,但它以 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", ]
这段代码的问题:
def get_location_queryset(self):
queryset = Location.objects.filter(location__owner=self.request.user)
return queryset
是基于函数的视图,您添加了 self
作为参数,并尝试访问 self
的上下文中不存在的 request
,因为 [=13] =] 值对我们来说是未定义的
我将如何通过创建基于 class 的位置过滤视图来根据用户过滤掉位置
class LocationView(ListView):
def get_queryset(self):
return Location.objects.filter(owner=self.request.user)
在filters.py中:
class ObjectFilter(django_filters.FilterSet):
location = django_filters.filters.ModelChoiceFilter(queryset=LocationView.as_view())
class Meta:
model = Object
fields = ["location", ]
我相信这里有几个不同的问题在起作用。首先,根据 django-filter docs,当可调用对象传递给 ModelChoiceFilter
时,它将以 Filterset.request
作为其唯一参数进行调用。所以你的 filters.py
需要像这样重写:
# filters.py
from .models import Object
import django_filters
def get_location_queryset(request): # updated from `self` to `request`
queryset = Location.objects.filter(location__owner=request.user)
return queryset
class ObjectFilter(django_filters.FilterSet):
location = django_filters.filters.ModelChoiceFilter(queryset=get_location_queryset)
class Meta:
model = Object
fields = ["location", ]
这是拼图的一半。我相信另一个问题在你看来。 django-filter
有视图 类 处理传递给过滤器集的请求,但这不会使用 Django 的通用 ListView
自动发生。尝试将您的视图代码更新为如下内容:
# views.py
from django_filters.views import FilterView
class ObjectListView(LoginRequiredMixin, FilterView): # FilterView instead of ListView
model = Object
filterset_class = ObjectFilter
这应该会为您传递请求。
另请注意,根据上面链接的 django-filter 文档,您的查询集应处理 request
为 None
的情况。我个人从未在我的项目中看到过这种情况,仅供参考。
作为替代方案,如果您不想使用 FilterView
,我相信您示例中的代码几乎就在那里:
# views.py alternative
class ObjectListView(LoginRequiredMixin, ListView):
model = Object
paginate_by = 10
def get_queryset(self):
filterset = ObjectFilter(self.request)
return filterset.qs
我认为这也适用于我上面指定的 filters.py
。