繁体   English   中英

Django-filter:具有基于 request.user 的查询集的 ModelChoiceFilter

[英]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 文档,您的查询集应处理requestNone的情况。 我个人从未在我的项目中看到过这种情况,仅供参考。

作为替代方案,如果您不想使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM