Python 是否可以过滤掉中间件中的一些数据库行?

Python 是否可以过滤掉中间件中的一些数据库行?,python,django,django-rest-framework,Python,Django,Django Rest Framework,很抱歉,这个问题太长了,我不能把它缩短,而且还是有意义的 我们有一个非常简单的应用程序,有两个简单的模型Company和Building,它们之间有多对多的关系。每个都有一个restricted属性User是一个常规的DjangoUser类,除了我们添加了一个show属性之外 #models.py 类用户(抽象用户): show=models.BooleanField(默认值=True) 公司类别(型号.型号): name=models.CharField(最大长度=100) restricte

很抱歉,这个问题太长了,我不能把它缩短,而且还是有意义的

我们有一个非常简单的应用程序,有两个简单的模型
Company
Building
,它们之间有多对多的关系。每个都有一个
restricted
属性
User
是一个常规的Django
User
类,除了我们添加了一个
show
属性之外

#models.py
类用户(抽象用户):
show=models.BooleanField(默认值=True)
公司类别(型号.型号):
name=models.CharField(最大长度=100)
restricted=models.BooleanField(默认值=False)
班级建设(models.Model):
name=models.CharField(最大长度=100)
restricted=models.BooleanField(默认值=False)
公司=模型.ManyToManyField(公司,相关的建筑)
视图是常规Django REST Framework视图集,序列化程序尽可能简单:

#views.py
类别CompanyViewSet(ModelViewSet):
queryset=Company.objects.all()
序列化程序\u类=公司序列化程序
类BuildingViewSet(ModelViewSet):
queryset=Building.objects.all()
serializer_class=BuildingSerializer
#序列化程序.py
类CompanySerializer(serializers.ModelSerializer):
类元:
模型=公司
字段='\uuuu所有\uuuu'
类BuildingSerializer(serializers.ModelSerializer):
类元:
模型=建筑物
字段='\uuuu所有\uuuu'
现在我们要实现此行为:如果
user.show
False
,则用户必须不能看到(在视图中)受限制的
公司和
建筑

换句话说,如果
john
用户
并且
john.show为False
john
可以(在视图中)看到
normal\u company
normal\u building
,但不是
受限公司
受限大楼

为了实现这一点,如果可能的话,我们不想编辑视图/序列化程序,因为它们太多了(这是实际项目的简化版本,要大得多)

我的团队考虑使用中间件。我们尝试动态更改
公司.objects
建筑.objects

#middleware.py
类filtermddware:
定义初始化(自我,获取响应):
self.get\u response=get\u response
定义呼叫(自我,请求):
user=get_user()#以某种方式获取用户。
如果不是user.show:
#替换对象。
对于(公司、建筑)中的模型:
model.objects=model.objects.filter(restricted=False)
响应=自我获取响应(请求)
返回响应
但是,由于某种未知的原因,这不起作用:
john
仍然可以看到受限制的公司。然后,我们尝试动态更新
django.db.models.Manager.get\u queryset
方法:

#middleware.py
类filtermddware:
定义初始化(自我,获取响应):
self.get\u response=get\u response
定义呼叫(自我,请求):
user=get_user()
如果不是user.show:
models.Manager.get_queryset=get_restricted_queryset
响应=自我获取响应(请求)
返回响应
def get_restricted_queryset(self、*args、**kwargs):
#过滤器的条件将在稍后公布。
隐藏条件={
“公司”:Q(受限=真实),
“建筑”:Q(公司受限=真实)| Q(受限=真实),
}
model\u name=self.model.\u name__
如果隐藏条件中的模型名称:
#我们必须过滤掉模型,所以应用隐藏条件。
隐藏条件=隐藏条件[模型名称]
返回self.\u queryset\u类(
model=self.model,使用=self.\u db,提示=self.\u提示
).exclude(隐藏条件)
其他:
返回self.\u queryset_类(model=self.model,using=self.\u db,hints=self.\u hints)
但这不起作用——这很奇怪:当我获取公司时,实际上只有
用户
模型被
获取查询集
调用,因此
获取受限查询集
没有效果

现在,我们真的被卡住了。有人有什么想法可以帮助我们吗?或者只是中间件不应该做这样的事情?

您不需要中间件(因为中间件只处理请求和响应,这是QuerySet下面的抽象级别)。您可以在DRF中使用自定义筛选器包执行此操作,例如: 更新:也筛选嵌套公司

from rest_framework import filters

class IsRestrictedFilterBackend(filters.BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        if request.user and user.is_authenticated and not user.show:
            if queryset.model and queryset.model in [Company, Building]:
                queryset = queryset.filter(restricted=False)
                if queryset.model == Building:
                    return queryset.filter(companies__restricted=False)
        return queryset
然后将此筛选器后端添加到设置中:

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['yourapp.filter_backends.IsRestrictedFilterBackend']
}
…或者您可以在视图集的基础上使用它:

class BuildingViewSet(ModelViewSet):
    queryset = Building.objects.all()
    serializer_class = BuildingSerializer
    filter_backends = [yourapp.filter_backends.IsRestrictedFilterBackend]

我通常不会这样做,但既然你是一个新用户,如果我的答案或任何其他作品,并解决您的问题,请把它标记为正确答案,按下票下面的投票按钮抱歉迟到的答案。它确实可以工作,但是您知道一种方法可以使它对序列化程序返回的嵌套字段也可以工作吗(不接触序列化程序)?例如,如果我获取某个与受限公司关联的建筑物,它将始终返回该受限公司。