简体   繁体   English

如何在不调用 API 的情况下从 DRF 中的 ModelViewSet 获取数据

[英]How to get data from ModelViewSet in DRF without calling an API call

I'm going to convert all my APIs into gRPC calls.我将把我所有的 API 转换为gRPC调用。 At the moment I was able to transfer all the ViewSet into gRPC (sample code added end of this question).目前我能够将所有ViewSet转移到gRPC 中(示例代码添加到这个问题的末尾)。 But ModelViewSet , it get an error like this.但是ModelViewSet ,它会出现这样的错误。

Traceback (most recent call last):
  File "/home/wasdkiller/PycharmProjects/ocsa/dataengine-service/venv/lib/python3.6/site-packages/grpc/_server.py", line 435, in _call_behavior
    response_or_iterator = behavior(argument, context)
  File "/home/wasdkiller/PycharmProjects/ocsa/dataengine-service/servicers/tenant/main.py", line 15, in get_tenant
    data = ClientViewSet().list(request=original_request, )
  File "/home/wasdkiller/PycharmProjects/ocsa/dataengine-service/common/lib/decorators.py", line 128, in wrapper_format_response
    final_data = call_func(func, self, request, transaction, exception, *args, **kwargs)
  File "/home/wasdkiller/PycharmProjects/ocsa/dataengine-service/common/lib/decorators.py", line 99, in call_func
    return func(self, request, *args, **kwargs)
  File "/home/wasdkiller/PycharmProjects/ocsa/dataengine-service/api_v1/viewsets.py", line 471, in list
    data = super().list(request, *args, **kwargs).data
  File "/home/wasdkiller/PycharmProjects/ocsa/dataengine-service/venv/lib/python3.6/site-packages/rest_framework/mixins.py", line 38, in list
    queryset = self.filter_queryset(self.get_queryset())
  File "/home/wasdkiller/PycharmProjects/ocsa/dataengine-service/venv/lib/python3.6/site-packages/rest_framework/generics.py", line 158, in filter_queryset
    queryset = backend().filter_queryset(self.request, queryset, self)
AttributeError: 'ClientViewSet' object has no attribute 'request'

So my viewsets.py look like this ( format_response decorator convert it to Response object)所以我的viewsets.py看起来像这样( format_response装饰器将其转换为Response对象)

class ClientViewSet(viewsets.ModelViewSet):
    queryset = Client.objects.all()
    serializer_class = ser.ClientSerializer

    @format_response(exception=False)
    def list(self, request, *args, **kwargs):
        data = super().list(request, *args, **kwargs).data
        # data = {}
        return data, True, HTTPStatus.OK, 'data retrieve successfully'

When I call this as an API, it works perfectly.当我将其称为 API 时,它可以完美运行。 But I want to do the same thing without calling an API.但我想在不调用 API 的情况下做同样的事情。 Here how I was solving it,这是我如何解决的,

from django.http import HttpRequest
from rest_framework.request import Request


# creating request object
django_request = HttpRequest()
django_request.method = 'GET'
drf_request = Request(django_request)

data = ClientViewSet().list(request=drf_request)
print(f'data: {data.data}')

The problem with the super() function in the ClientViewSet , but if I uncomment data = {} and comment out the calling super() function, it works both API and the above method. ClientViewSet 中的super() ClientViewSet的问题,但是如果我取消注释data = {}并注释掉调用super() function,它适用于 ZDB974238714CA81434A7CE1D03 和上述方法。 I go through inside the DRF code base where error occurred, when calling the API the self object has the request object and above method it doesn't exist. I go through inside the DRF code base where error occurred, when calling the API the self object has the request object and above method it doesn't exist.

In short, you need to call as_view() on the viewset and map the http verbs, and then call that function with a proper HttpRequest.简而言之,您需要在视图集上调用as_view()和 map http 动词,然后使用适当的 HttpRequest 调用 function。

All views in django end up being functions, DRF is sugar on top of that. django 中的所有视图最终都是函数,DRF 是最重要的糖。 A "ViewSet" doesn't exist in the normal way, as a standalone class, after routing is complete.路由完成后,“ViewSet”以正常方式不存在,作为独立的 class。

django_request = HttpRequest()
django_request.method = 'GET'

my_view = ClientViewSet.as_view({'get': 'list', 'post':'create'})
data = my_view(request=django_request)
print(f'data: {data.data}')

If you want the detail routes ( users/37 , ...), then you need to create a new view function mapping to those viewset functions.如果您想要详细路线( users/37 ,...),那么您需要创建一个新视图 function 映射到这些视图集函数。 This can't be the same view function because http get now needs to point to a different function on the viewset than in the list case.这不可能是同一个视图 function 因为get现在需要在视图集中指向不同的 function 而不是列表案例。 See routers.py source for whats going on and what is mapped where.查看routers.py 源代码了解发生了什么以及映射到哪里。

# map http 'get' to the 'retrive' function on the viewset
my_view = ClientViewSet.as_view({'get': 'retrieve', ...})

# pass in the kwarg the URL routing would normally extract
client_pk = 9329032 
data = my_view(request=django_request, pk=client_pk)

If you want to see what all the mappings for your viewset are, then you an print them out using this snippet:如果您想查看视图集的所有映射是什么,那么您可以使用以下代码段将它们打印出来:

router = SimpleRouter()
router.register("client", ClientViewSet, basename="client")
for url in router.urls:  # type: URLPattern
    print(f"{url.pattern} ==> {url.callback}")
    for verb, action in url.callback.actions.items():
        print(f"    {verb} -> {action}")

# output will be something like this
^client/$ ==> <function ClientViewSet at 0x11b91c280>
    get -> list
^client/(?P<pk>[^/.]+)/$ ==> <function ClientViewSet at 0x11b91c3a0>
    get -> retrieve
    put -> update
    patch -> partial_update
    delete -> destroy

The kwargs you pass to this view will depend on the settings in your ViewSet for things like lookup_url_kwarg , but in most cases they will be simple.你传递给这个视图的kwargs将取决于你的 ViewSet 中的设置,比如lookup_url_kwarg ,但在大多数情况下它们会很简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM