如何在不调用 API 调用的情况下从 DRF 中的 ModelViewSet 获取数据
How to get data from ModelViewSet in DRF without calling an API call
我要将我所有的 API 转换成 gRPC calls. At the moment I was able to transfer all the ViewSet into gRPC(sample code added end of this question). But 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'
所以我的 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'
当我将其称为 API 时,它工作得很好。但是我想在不调用 API 的情况下做同样的事情。我是这样解决的,
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}')
ClientViewSet
中 super()
函数的问题,但是如果我取消注释 data = {}
并注释掉调用 super()
函数,它既有效 API 和上面的方法。我在发生错误的 DRF 代码库中进行了遍历,当调用 API 时,self
对象具有 request
对象并且上面的方法不存在。
简而言之,您需要在视图集上调用 as_view()
并映射 http 动词,然后使用适当的 HttpRequest 调用该函数。
django 中的所有视图最终都是函数,DRF 是最上面的糖。在路由完成后,"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}')
如果你想要详细的路线(users/37
, ...),那么你需要创建一个新的视图函数映射到那些视图集函数。这不能是相同的视图函数,因为 http get
现在需要指向视图集上与列表案例中不同的函数。请参阅 routers.py source 了解发生了什么以及映射到哪里。
# 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)
如果您想查看 所有 视图集的映射是什么,那么您可以使用以下代码段将它们打印出来:
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
您传递给此视图的 kwargs
将取决于您的 ViewSet 中的设置,例如 lookup_url_kwarg
,但在大多数情况下它们很简单。
我要将我所有的 API 转换成 gRPC calls. At the moment I was able to transfer all the ViewSet into gRPC(sample code added end of this question). But 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'
所以我的 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'
当我将其称为 API 时,它工作得很好。但是我想在不调用 API 的情况下做同样的事情。我是这样解决的,
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}')
ClientViewSet
中 super()
函数的问题,但是如果我取消注释 data = {}
并注释掉调用 super()
函数,它既有效 API 和上面的方法。我在发生错误的 DRF 代码库中进行了遍历,当调用 API 时,self
对象具有 request
对象并且上面的方法不存在。
简而言之,您需要在视图集上调用 as_view()
并映射 http 动词,然后使用适当的 HttpRequest 调用该函数。
django 中的所有视图最终都是函数,DRF 是最上面的糖。在路由完成后,"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}')
如果你想要详细的路线(users/37
, ...),那么你需要创建一个新的视图函数映射到那些视图集函数。这不能是相同的视图函数,因为 http get
现在需要指向视图集上与列表案例中不同的函数。请参阅 routers.py source 了解发生了什么以及映射到哪里。
# 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)
如果您想查看 所有 视图集的映射是什么,那么您可以使用以下代码段将它们打印出来:
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
您传递给此视图的 kwargs
将取决于您的 ViewSet 中的设置,例如 lookup_url_kwarg
,但在大多数情况下它们很简单。