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