【发布时间】:2016-10-20 07:56:52
【问题描述】:
如何覆盖多个 ViewSet 的 POST、PATCH 和 DELETE 方法以允许我添加强制后端参数?
逻辑。我正在构建一个多租户应用程序,该应用程序在所有相关表中都有一个“tenant_id”。此tenant_id 标识租户,因此所有请求都必须包含此父键,以避免用户看到/修改不属于他们的内容。
对于 Get 查询,我创建了一个自定义过滤器后端,它使我能够添加强制过滤器对象来限制用户可以获得的内容
class CustomFilterBackend(filters.BaseFilterBackend):
"""
Filter that only allows users to see entries related to their tenant.
"""
def filter_queryset(self, request, queryset, view):
tenant_id = get_tenant_id_from_token(request)
return queryset.filter(is_deleted=False, tenant_id=tenant_id)
然后我通过 filter_backends = () 选项将此过滤器添加到所有 ViewSet 类中
问题是,有没有办法为 POST、PATCH、DELETE 请求实现相同的功能?
我目前的想法是对所有模型都覆盖model.save 方法?但这不会处理 HTTP DELETE 方法。
透明的tenant_id:
在模型中,tenant_id 当然是强制性的。但是,我不想强制 Web/移动客户端始终提供tenant_id,因为我可以从用户的 JWT 令牌中获取它。即tenant_id 应该对网络/移动应用程序是透明的。
编辑 2
问题是,我想在网络/移动应用程序不知情的情况下静默/安静/幕后添加tenant_id。这意味着我不希望使用 API 的应用程序发送 tenant_id JSON 密钥。
样本模型
class SampleModel(models.Model):
"""
Sample model
"""
title = models.CharField(max_length=100)
tenant = models.ForeignKey(Tenant, on_delete=models.PROTECT)
class CustomFilterBackend(filters.BaseFilterBackend):
"""
Filter that only allows users to see entries related to their tenant.
"""
def filter_queryset(self, request, queryset, view):
tenant_id = get_tenant_id_from_token(request)
return queryset.filter(is_deleted=False, tenant_id=tenant_id)
class SampleViewSet(ListCreateRetrieveUpdateViewSet):
"""
Sample viewset
"""
serializer_class = SampleModelSerializer
permission_classes = (HasPermission)
queryset = SampleModel.objects.all()
filter_backends = (CustomFilterBackend, )
通过将 filter_backends 添加到所有视图集,所有 GET 查询现在都包含一个tenant_id。所以我想要的是对所有其他 HTTP 方法,尤其是 POST 和 PATCH 实现相同的效果
从阅读看来我必须重写序列化程序?是否有可能以 DRY 方式进行?到现在还没想好怎么弄
在创建自定义 jwt_payload_handler 后,获取tenant_id 的 JWT 的 Payload 如下所示:
{
"exp": 1477069682,
"is_superuser": true,
"email": "test-email@gmail.com",
"tenant_id": 1, #THE TENANT ID
"user_id": 1,
"username": "test-email@gmail.com"
}
【问题讨论】:
标签: django django-views django-rest-framework