[英]Django-Filter: ModelChoiceFilter using queryset related to the current user
[英]Django-filter: ModelChoiceFilter with request.user based queryset
我有一個基於 Django 類的 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", ]
我相信這里有幾個不同的問題在起作用。 首先,根據django-filter 文檔,當一個可調用對象被傳遞給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
。
這段代碼的問題:
def get_location_queryset(self):
queryset = Location.objects.filter(location__owner=self.request.user)
return queryset
是它是基於函數的視圖,您將self
添加為參數,並嘗試訪問在self
上下文中不存在的request
,因為self
值對我們來說是未定義的
通過為位置過濾創建基於類的視圖,我將如何根據用戶過濾位置
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", ]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.