Django 覆盖POST、PATCH&;删除方法

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

如何覆盖多个视图集的POST、PATCH和DELETE方法,以允许添加必需的后端参数

逻辑。我正在构建一个多租户应用程序,它在所有相关表中都有一个“租户id”。此租户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\u backends=()
选项将此过滤器添加到所有视图集类中

问题是,有没有一种方法可以实现同样的POST、补丁和删除请求

我目前的想法是,可以覆盖
模型。是否为所有模型保存
方法?但这不会考虑HTTP
DELETE
方法

透明租户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())