【问题标题】:Django rest framework- calling another class-based viewDjango rest framework-调用另一个基于类的视图
【发布时间】:2018-12-11 05:47:13
【问题描述】:

我仔细研究了几篇类似的帖子(Calling a class-based view of an app from another app in same project 似乎很有希望,但不起作用),但有些比较老,没有一个对我有用。这是我的设置(使用 Django==2.0.6,djangorestframework==3.8.2)

我有一个基本模型(这里简化了):

from django.db import models
class Resource(models.Model):
    name = models.CharField(max_length=100, null=False)

我有一个基本端点,我可以在其中列出和创建 Resource 实例:

from rest_framework import generics, permissions
from myapp.models import Resource
from myapp.serializers import ResourceSerializer

class ListAndCreateResource(generics.ListCreateAPIView):
    queryset = Resource.objects.all()
    serializer_class = ResourceSerializer
    permission_classes = (permissions.IsAuthenticated,)

(afaik,序列化程序的细节不相关,所以省略了)。

无论如何,除了那个基本端点之外,我还有另一个 API 端点,它执行一些操作,但也在这个过程中创建了一些 Resource 对象。当然,我想利用封装在ListAndCreateResource 类中的功能,所以我只需要维护一个创建Resources 的地方。

我试过了:

尝试 1:

class SomeOtherView(generics.CreateAPIView):
    def post(self, request, *args, **kwargs):
        # ... some other functionality...
        # ...
        response = ListAndCreateResource().post(request, *args, **kwargs)
        # ... more functionality...
        return Response({'message': 'ok'})

不幸的是,这对我不起作用。在我的跟踪中,我得到:

  File "/home/projects/venv/lib/python3.5/site-packages/rest_framework/generics.py", line 111, in get_serializer
    kwargs['context'] = self.get_serializer_context()
  File "/home/projects/venv/lib/python3.5/site-packages/rest_framework/generics.py", line 137, in get_serializer_context
    'request': self.request,
AttributeError: 'ListAndCreateResource' object has no attribute 'request'

尝试 2: 此尝试尝试使用 as_view 方法,该方法是所有基于 Django 类的视图的一部分:

class SomeOtherView(generics.CreateAPIView):
    def post(self, request, *args, **kwargs):
        # ... some other functionality...
        # ...
        response = ListAndCreateResource.as_view()(request, *args, **kwargs)
        # ... more functionality...
        return Response({'message': 'ok'})

但这放弃了:

AssertionError: The `request` argument must be an instance of `django.http.HttpRequest`, not `rest_framework.request.Request`

所以我的问题是...有没有一种简单的方法可以做到这一点?我可以访问rest_framework.request.Request 对象的_request 属性(类型为django.http.HttpRequest,但是我没有任何包含在DRF Request 对象中的身份验证详细信息(实际上,我的@987654337如果我在上面的尝试#2 中使用response = ListAndCreateResource().as_view()(request._request, *args, **kwargs),@ 返回 403)。

提前致谢!

【问题讨论】:

  • 我想一种可能的选择是将执行验证和对象创建的代码(代码通常在 rest_framework.mixins.CreateModelMixin.create 中运行)移动到其他一些函数(在两个类之外)并具有这两个视图使用该功能。这并没有让我觉得特别优雅,我很惊讶这在其他与 DRF 相关的 SO 线程中之前没有出现过。
  • 我同意你的看法@blawney_dfci 应该有一种更简单的方法来重用休息服务视图类。同样的问题:几个 api 已经可以使用,我需要从 python 方面调用它们。猜猜他们真的想断开视图和模型/控制。
  • 第一种方法对我有用,但序列化程序的工作方式很奇怪

标签: django django-rest-framework django-views


【解决方案1】:

这似乎有点晚了,但以防有人想知道。

class SomeOtherView(generics.CreateAPIView):
    def post(self, request, *args, **kwargs):
        # ... some other functionality...
        # ...
        response = ListAndCreateResource.as_view()(request, *args, **kwargs)
        # ... more functionality...
        return Response({'message': 'ok'})

as_view() 是一个函数,当被调用时,它会返回一个接受请求的函数,*args,**kwargs。所以基本上,类视图是一个封装的函数视图。

【讨论】:

  • 我收到以下错误消息 [request 参数必须是 django.http.HttpRequest 的实例,而不是 rest_framework.request.Request]。有解决办法吗?
  • @AmanSharma 使用 request._request,DRF 请求是 django request 的包装,可以使用 ._request 访问
【解决方案2】:

您可以在基于类的视图中使用self.request 访问request

【讨论】:

  • 我确实知道这么多,但也许我误解了你的回答。问题(尝试#2)是self.request 的类型为rest_framework.request.Request。在尝试#1 中,我无法创建具有request 属性集的ListAndCreateResource 实例。如果我明确设置它,我只会得到我正在创建的 ListAndCreateResource 对象的其他缺失属性错误。
  • 我阅读了您的问题并回答了另一件事,也许可以尝试阅读this
  • 我可以通过链接该线程(提供一些替代方法)来了解您要去哪里,但我希望有一种更直接的方法,而不必求助于一堆被覆盖的方法。还是谢谢。
【解决方案3】:

我认为你可以使用 request._request。 DRF 保留从 API 调用接收到的受保护成员 _request。

【讨论】: