как переписать класс ответа в django rest framework (DRF)? - PullRequest
0 голосов
/ 24 декабря 2018

Я хочу перезаписать Response класс фреймворка django так, чтобы ответный словарь обратной реакции содержал три параметра message, status и data

Здравствуйте, дорогие все

Я пытаюсь изменить Response Class в DRF, чтобы передать два дополнительных параметра (сообщение, статус) плюс данные, предоставляемые сериализатором DRF.message передает сообщение типа Done, User Created или т. Д. И status передает сообщение типа fail или success или т. Д., И это сообщение полезно для резервирования специального кода между внешним интерфейсом и внутренним интерфейсом.

Я хочу, чтобы, если не установить этот параметр, вернуть пустой символ или нулевой результат обратно на клиентскую сторону

, например, в режиме успеха:

{
    'data': {
        'value_one': 'some data',
        'value_two': 'some data',
        'value_three': [
                'value', 'value', 'value'
            ],
        },
    }
    'message': 'Done',
    'status': 'success',
}

и в режиме сбоя:

{
    'data': ['any error message raise by serializer',]
    'message': 'Create User Failed',
    'status': 'failure',
}

Я ищу свой вопрос и нашел решение:

, если я унаследую DRF Response Class в своем классе и перезаписываю __init__ метод и получаю сообщение, данные и статус в этом методе ивызовите init родительского объекта с собственной структурой данных и используйте этот отзывчивый класс в моей функциональности, например:

from rest_framework.response import Response


class Response(Response):

    def __init__(self, data=None, message=None, data_status=None, status=None,
                template_name=None, headers=None,
                exception=False, content_type=None):

        data_content = {
            'status': data_status,
            'data': data,
            'message': message,
        }
        super(Response, self).__init__(
            data=data_content,
            status=status,
            template_name=template_name,
            headers=headers,
            exception=exception,
            content_type=content_type
        )

в режиме успеха; вызов:

return Response(data=serializer.data, message='Done', data_status='success', status=200)

inвызов режима сбоя:

return Response(data=serializer.errors, message='Create User Failed', data_status='failure', status=400)

и использование собственного класса Response во всех классах представлений, которые мы имели problem в этом решении: если мы используем GenericViews Class, необходимо перезаписать все методы http, которые мы использовали в логике представления и вызовесобственный класс, и это DRY !!


и другое решение, которое я нашел.в сериализованном слое мы имеем абстрактный метод def to_representation(self, instance): в Serializer классе и реализуем в другом классе, например ModelSerializer наследование класса Serializer, и если мы перезаписываем этот метод в нашем сериализаторе и повторно выбираем данные перед отправкой в ​​слой представления,реализовать как:

from collections import OrderedDict

class OurSerializer(serializer.ModelSerializer):

....

    def to_representation(self, instance):
        data = super(serializers.ModelSerializer, self).to_representation(instance)
        result = OrderedDict()
        result['data'] = data
        result['message'] = 'Done'
        result['status'] = 'sucssed'
        return result

это решение решает вышеуказанную проблему, но у нас снова есть две проблемы

одна: если мы используем вложенный сериализатор и нам пришлось перезаписать эту функцию в классе сериализатора, вернуть неверные данные, такие как:

{
    'data': {
        'value_one': 'some data',
        'value_two': 'some data',
        'value_three': {
            'data': [
                'value', 'value', 'value'
            ],
            'message': 'Done',
            'status': 'sucssed',
        },
    }
    'message': 'Done',
    'status': 'sucssed',
}

и message и status повторяются и структура не очень привлекательна для клиента

и два: мы не можем обработать исключение в этом режиме и просто способ обработать исключение только с помощью класса промежуточного программного обеспечениякак это Обработка исключений DRF , и это бесполезный способ, мы не можем обрабатывать любые типы ошибок, возникающих в поле зрения, и генерировать удобные отдельные message и status.

IFесть еще одно хорошее решение этого вопроса, пожалуйста, наведите меня.

спасибо:)

Ответы [ 2 ]

0 голосов
/ 26 декабря 2018

Для решения этой проблемы рекомендуется использовать классы рендерера (которые предлагает DRF).Рендерер манипулирует и возвращает структурированный ответ.

Django использует рендереры, такие как Template Renderer и DRF, которые поддерживают эту функцию и предоставляют API рендеринг * .

.Итак, вы можете предоставить такой рендерер в пакете (например, app_name.renderers.ApiRenderer):

from rest_framework.renderers import BaseRenderer
from rest_framework.utils import json


class ApiRenderer(BaseRenderer):

    def render(self, data, accepted_media_type=None, renderer_context=None):
        response_dict = {
            'status': 'failure',
            'data': {},
            'message': '',
        }
        if data.get('data'):
            response_dict['data'] = data.get('data')
        if data.get('status'):
            response_dict['status'] = data.get('status')
        if data.get('message'):
            response_dict['message'] = data.get('message')
        data = response_dict
        return json.dumps(data)

А затем в вашем файле настроек:

REST_FRAMEWORK = {
    ...
    'DEFAULT_RENDERER_CLASSES': (
        'app_name.renderers.ApiRenderer',
    ),
    ...
}

Этим действием все представления, которые расширяютсяОбщие представления DRF будут использовать рендерер.Если вам нужно переопределить настройку, вы можете использовать атрибут renderer_classes для классов общего представления и @renderer_classes декоратор для функций представления API.

Полный класс рендерера для переопределения доступен в <virtualenv_dir>/lib/python3.6/site-packages/rest_framework/renderers.py.

0 голосов
/ 24 декабря 2018

Вы пытались написать пользовательское промежуточное ПО для ответа:

class ResponseCustomMiddleware(MiddlewareMixin):
    def __init__(self, *args, **kwargs):
        super(ResponseCustomMiddleware, self).__init__(*args, **kwargs)

    def process_template_response(self, request, response):

        if not response.is_rendered and isinstance(response, Response):
            if isinstance(response.data, dict):
                message = response.data.get('message', 'Some error occurred')
                if 'data' not in response.data:
                    response.data = {'data': response.data}
                response.data.setdefault('message', message)
                # you can add you logic for checking in status code is 2** or 4**.
                data_status = 'unknown'
                if response.status_code // 100 == 2:
                    data_status = 'success'
                elif response.status_code // 100 == 4:
                    data_status = 'failure'
                response.data.setdefault('data_status', data_status)
        return response

Добавить промежуточное ПО в настройках:

MIDDLEWARE = [
    # you all middleware here,
    'common.middleware.ResponseCustomMiddleware',
]

Таким образом, вы можете вернуть Response следующим образом:

data = {'var1': 1, 'var2': 2}
return Response({'data': data, 'message': 'This is my message'}, status=status.HTTP_201_CREATED)

Ответ будет таким:

{
  "data": [
    {
        "var1": 1,
        "var2": 2
    }
  ],
  "message": "This is my message",
  "data_status": "success"
}
...