Django 覆盖POST、PATCH&;删除方法
如何覆盖多个视图集的POST、PATCH和DELETE方法,以允许添加必需的后端参数 逻辑。我正在构建一个多租户应用程序,它在所有相关表中都有一个“租户id”。此租户id标识租户,因此所有请求都必须包含此父密钥,以避免用户看到/修改非他们的内容 对于Get查询,我创建了一个自定义筛选器后端,它允许我添加一个强制筛选器对象来限制用户可以获取的内容Django 覆盖POST、PATCH&;删除方法,django,django-views,django-rest-framework,Django,Django Views,Django Rest Framework,如何覆盖多个视图集的POST、PATCH和DELETE方法,以允许添加必需的后端参数 逻辑。我正在构建一个多租户应用程序,它在所有相关表中都有一个“租户id”。此租户id标识租户,因此所有请求都必须包含此父密钥,以避免用户看到/修改非他们的内容 对于Get查询,我创建了一个自定义筛选器后端,它允许我添加一个强制筛选器对象来限制用户可以获取的内容 class CustomFilterBackend(filters.BaseFilterBackend): """ Filter tha
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\u backends=()
选项将此过滤器添加到所有视图集类中
问题是,有没有一种方法可以实现同样的POST、补丁和删除请求
我目前的想法是,可以覆盖模型。是否为所有模型保存方法?但这不会考虑HTTPDELETE
方法
透明租户id:
在模型中,租户id当然是必需的。但是,我不想强制web/mobile客户端始终提供租户id,因为我可以从用户的JWT令牌获得它。i、 e.租户id应对网络/移动应用程序透明
编辑2
问题是,我想悄悄地/悄悄地/幕后添加一个租户id
,而不让web/移动应用程序察觉。这意味着我不希望使用API的应用程序发送tenant\u 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_后端,所有GET查询现在都包含一个租户id。因此,我想对所有其他HTTP方法实现相同的功能,尤其是POST和PATCH
从阅读来看,似乎我必须重写序列化程序?可以用干燥的方式做吗?到目前为止,我还不知道该怎么做
在创建自定义JWT\u Payload\u处理程序后,获取租户id的JWT有一个如下所示的负载:
{
"exp": 1477069682,
"is_superuser": true,
"email": "test-email@gmail.com",
"tenant_id": 1, #THE TENANT ID
"user_id": 1,
"username": "test-email@gmail.com"
}
如果您试图弄清楚如何将Id传递给视图,那么答案很简单<代码>Id主要通过URL传递给视图
。尝试GET
请求您的查询集,id如下
api/url/endpoint/1
1将通过drf路由器从URL传递到视图。然后,根据http方法
,在您的情况下是GET,选择适当的操作。例如,如果您使用GET、PUT、PATCH或DELETE
方法调用上述url,则方法1被视为对对象Id的引用,然后执行orm查询,可以
model.objects.get(id=1) #if request.method is GET
model.objects.get(id=1).delete() #if request.method is DELETE
model.objects.get(id=1) #if request.method is PATCH or PUT and then the fields of the corresponding object will be updated.
如果将POST
请求传递给api端点,通常情况下,将通过api端点标识模型名称,然后使用传递的参数创建新对象
现在回答另一部分。在大多数情况下,drf返回类响应的对象
,浏览器和移动设备可以将其用作JSON
对象。但在涉及drf视图集的场景中,这些响应不会从get()之类的方法返回。在这些情况下,通常最后一个函数(大多数情况下是render\u to\u response()
将返回响应
HTH我建议使用,并创建一个类来获取租户,就像CurrentUserDefault
那样
例如,如果要设置当前登录用户的租户(独立于其身份验证方式、令牌、会话…):
如果不使用Django身份验证(应该!),请查看的实现,以了解如何从请求中获取租户(确保返回租户实例,而不是其id,这可能不起作用)
可能是这样的:
class CurrentTenantDefault():
def set_context(self, serializer_field):
request = serializer_field.context['request']
tenant_id = get_tenant_id_from_token(request)
self.tenant = Tenant.objects.get(pk=tenant_id)
def __call__(self):
return self.tenant
然后在序列化程序中声明隐藏字段,如下所示:
tenant = serializers.HiddenField(default=CurrentTenantDefault())
注意:您不应该在模型中声明名称以“\u id”结尾的外键
,因为在实例化模型时,实例。租户
是租户实例,不是租户ID。Django将外键存储在租户ID列中,但这是透明的,您不需要关心它。我不想知道如何传递ID。我已经编辑了这个问题,并提供了更多的清晰度。看看这个问题现在是否有意义。我正在使用Django的身份验证。另外,ForeignKey
不是使用\u id
声明的,我已经更正了我给出的示例模型。在您的建议中,我将把CurrentTenantDefault
放在哪里?此外,租户标识符将从JWT令牌的私有部分获取。我正在使用django rest framework jwt
,在登录时,我将租户id添加到令牌中。请参阅我添加到问题中的示例。我通常将其保存在序列化程序
模块中,或者当序列化程序拆分为多个模块时,将其保存在类似序列化程序.core
的模块中。我已经用CurrentTenantDefault
的例子更新了答案,使用了get\u tenant\u id\u from\u token
函数。谢谢先生。这就像预期的一样,而且很容易理解
tenant = serializers.HiddenField(default=CurrentTenantDefault())