Есть ли способ определить тип запроса, полученного в представлении на основе классов с Django Rest Framework? - PullRequest
0 голосов
/ 22 сентября 2019

У меня есть служба API Django Rest Framework , которую я хочу повторно использовать в своем приложении внешнего интерфейса , но у меня есть некоторые сомнения относительно лучшего способа определения типа запроса, который получает конечная точка.

У меня есть структура, подобная приведенной ниже:

core
api
web

И я вызываю свои конечные точки из моего веб-приложения в мое приложение API.На данный момент я не использую никакой интерфейсной среды, только django, поэтому я отправляю данные из своего веб-приложения в API следующим образом: _customdictionary.custom_dictionary_kpi ({"language": 1, "user": 1}) , посмотрите, что в этом случае я не выполняю запрос POST, я просто отправляю словарь только с двумя значениями: language и user , которые я определил вмои сериализаторы:

serializers.py

class CustomDictionaryKpiSerializer(serializers.ModelSerializer):
    class Meta:
        model = CustomDictionary
        fields = ('user','language')

web / views.py

class CustomDictionaryView(View):
    def get(self, request, *args, **kwargs):
        try:
            _customdictionary = CustomDictionaryViewSet()
            _customdictionary.custom_dictionary_kpi({"language": 1, "user": 1}) # Here i send my data
            '''some logic'''            
        except Exception as e:
            '''handle exception'''
        return render(request,template_name='web/dictionary_get.html',status=self.code,context=self.response_data)

Затем я получаю данные в api / api.py с request ['field_name']

class CustomDictionaryViewSet(viewsets.ModelViewSet):
    queryset = CustomDictionary.objects.filter(
        is_active=True,
        is_deleted=False
    ).order_by('id')
    permission_classes = [
        permissions.AllowAny
    ]
    pagination_class = StandardResultsSetPagination

    def __init__(self,*args, **kwargs):
        self.response_data = {'error': [], 'data': {}}
        self.code = 0

    def get_serializer_class(self):
        if self.action == 'custom_dictionary_kpi':
            return CustomDictionaryKpiSerializer
        return CustomDictionarySerializer

    @action(methods=['post'], detail=False)
    def custom_dictionary_kpi(self, request, *args, **kwargs):
        try:
            queryset = CustomDictionary.objects.filter(
                is_active=True,
                is_deleted=False,
                language_id=request['language'],
                user_id=request['user']
            ).order_by('id')
                '''some logic'''
        except Exception as e:
            '''handle error'''
        return Response(self.response_data,status=self.code)

Проблема заключается в том, что если я отправляю запрос POST в API DRF (форма HTML), перехватывая запрос, например: request ['field_name']

Не работает по причине:

*** TypeError: 'Request' object is not subscriptable

Работает с:

request.POST.get('<field_name>')

Или

request.data['<field_name>']

Получениепользователь или язык в типе Str.Аналогичная проблема возникает, если я отправляю данные в DFR API, но в необработанных данных он не работает с: request['field_name']

По причине:

*** TypeError: 'Request' object is not subscriptable

Ни с одним из них:

request.POST.get('<field_name>')

Поскольку его нет, он работает с:

request.data['<field_name>']

Получение пользователя или языка в типе Integer.Я знаю, что если я использую инфраструктуру веб-интерфейса, я мог бы отправить запрос на свою конечную точку и затем получить данные таким же образом, как DRF API:

request.POST.get('<field_name>')

или

request.data['<field_name>']

Я предполагаю, что мне нужен метод, который проверяет тип запроса, что-то вроде:

def validate(self,request):
   try:
      if request['field_name']:
         '''some logic'''
   except Exception as e:
      if request.POST.get('field_name'):
         '''some logic'''

Итак, есть ли элегантный способ проверки типа запроса?

Заранее спасибо залюбая помощь

Ответы [ 3 ]

1 голос
/ 22 сентября 2019

Если этот метод validation является общим для некоторых конечных точек, одним из лучших методов является использование декоратора для проверки некоторой информации из объекта запроса.Скажем, в decorators.py у нас есть validate_field_name декоратор, который полезен custom_dictionary_kpi проверки конечной точки API.Итак

В decorators.py

from functools import wraps
from rest_framework import exceptions


def validate_field_name(f):
    @wraps(f)
    def decorator(self, request, *args, **kwargs):
        errors = {}
        try:
            if request['field_name']:
                '''some logic'''
        except Exception as e:
            if request.POST.get('field_name'):
                '''some logic'''
        if errors:
            raise exceptions.ValidationError(errors)
        return f(self, request, *args, **kwargs)

    return decorator

И в наших views.py

from .decorators import validate_field_name

class CustomDictionaryViewSet(viewsets.ModelViewSet):
    "" All your necessary codes "" 
    @validate_field_name
    @action(methods=['post'], detail=False)
    def custom_dictionary_kpi(self, request, *args, **kwargs):
        try:
            queryset = CustomDictionary.objects.filter(
                is_active=True,
                is_deleted=False,
                language_id=request['language'],
                user_id=request['user']
            ).order_by('id')
                '''some logic'''
        except Exception as e:
            '''handle error'''
        return Response(self.response_data,status=self.code)

Ссылки

  1. что такое декораторы в python ссылка
  2. functools
0 голосов
/ 23 сентября 2019

Согласно ответу @Shakil и типу запроса, как сказал @Abhimanyu Singh, это было мое решение, я надеюсь, что оно будет полезным для всех остальных:

В случае CBV (в web / views.py), отправка параметров, таких как:

_instance= MyNameViewSet()
_instance.endpoint_name(request,param1=1,param2=1)

Проверка запроса выглядит так:

from functools import wraps
from rest_framework import exceptions

def validate_field_name(f):
    @wraps(f)
    def decorator(*args, **kwargs):
        if(len(kwargs) > 0):
            # HTML template
            kwargs['data'] = kwargs
        # DRF API View, Postman POST request made by body (JSON)
        elif len(args[1].data) > 0:
            kwargs['data'] = args[1].data
        # Postman POST request made by params
        elif len(args[1].query_params.dict()) > 0:
            kwargs['data'] = args[1].query_params.dict()
        return f(*args,**kwargs)
    return decorator

Это возвращает dict, тогда в вашем api.py вы можете получить доступ как:

kwargs['data']['param1']
0 голосов
/ 22 сентября 2019

Проблема в том, что вы используете объект запроса mxing django и DRF.Потому что при каждом запросе Django устанавливает объект запроса, содержащий несколько заголовков.Но DRF расширяет этот HttpRequest объект https://docs.djangoproject.com/en/2.2/ref/request-response/ как объект Request DRF, указанный в https://www.django -rest-framework.org / api-guide / запросы / .Таким образом, чтобы понять, какой тип запроса вы получаете, посмотрите атрибуты.Например, данные POST Django присутствуют в request.POST объекте запроса, но для DRF они представлены в request.data.Аналогично, в django данные GET присутствуют в request.DATA, но для DRF - в request.query_params.Для получения дополнительной информации см. Ссылку на документацию, приведенную выше.

...