Как получить данные из ModelViewSet в DRF без вызова вызова API - PullRequest
1 голос
/ 30 апреля 2020

Я собираюсь преобразовать все свои API в gRP C вызовов. На данный момент я смог перевести все ViewSet в gRP C (пример кода добавил конец этого вопроса). Но 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}')

Проблема с функцией super() в ClientViewSet, но если я раскомментирую data = {} и закомментирую вызывающую функцию super(), она работает как API и вышеуказанный метод. Я go через базу кода DRF , где произошла ошибка, при вызове API объект self имеет объект request, а над методом его нет.

1 Ответ

1 голос
/ 30 апреля 2020

Короче говоря, вам нужно вызвать as_view() в наборе и сопоставить глаголы http, а затем вызвать эту функцию с правильным HttpRequest.

Все представления в django в конечном итоге являются функциями, DRF - это сахар. «ViewSet» не существует обычным способом, как отдельный класс, после завершения маршрутизации.

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 , что происходит и где отображается.

# 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, но в большинстве случаев они будут просто.

...