djangorestframework开发配置

时间:2023-02-03 19:02:06
  • django 和 restframework 结合。对api再次封装返回非浏览器状态码
  • 基础模型封装
  • 分页格式调整
{
  "msg": 'success',
  "code": 200,
  "data": []
}

后端目录设置

- project
	- apps # 模块
	- project # 项目配置
	- utils # 封装api
		- exceptions.py
		- response.py
		- minxins.py
		- views.py
		- viewsets.py
		- models.py

response

基础api如APIView, GenericAPIView 重构 from rest_framework.response import Response

response.py


from rest_framework.response import Response


class CustomResponse(Response):

    def __init__(self, data=None, status=200, code=200, msg='success', template_name=None, headers=None,
                 exception=False, content_type=None):
        super().__init__(data, status, template_name, headers, exception, content_type)

        self.data = {
            'data': [] if data is None else data,
            'code': code,
            'msg': msg
        }

minxins

mixins.py

如果使用ListModelMixin RetrieveModelMixin UpdateModelMixin DestroyModelMixin重新构造Response

from rest_framework import mixins
from utils.response import CustomResponse


class CustomCreateModelMixin(mixins.CreateModelMixin):

    def create(self, request, *args, **kwargs):
        response = super().create(request, *args, **kwargs)
        return CustomResponse(data=response.data)

如果使用DestroyModelMixin逻辑删除可以重构

def perform_destroy(self, instance):
    """
    存在逻辑删除,逻辑删除,否则直接删除
    """
    try:
        instance.is_delete = True
    except AttributeError:
        instance.delete()
    else:
        instance.save()

exceptions

逻辑例如 封装接口调用,接口不易直接返回Response需要多次判断处理)中可以直接抛出自定义异常,在exceptions中捕捉异常!

drf序列化起验证权限认证异常,抛出格式不同。所以,在处理前端根据返回结果中msg展示给用户时需要根据真实情况处理。推荐后端处理

exceptions.py

from rest_framework.views import (
    exception_handler, status, Response, set_rollback, exceptions
)

from django.http import Http404
import logging

logger = logging.getLogger('django')


class CustomException(Exception):
    # 自定义code
    default_code = 400
    # 自定义 message
    default_message = None

    def __init__(
            self,
            status_code=status.HTTP_200_OK,
            code: int = None,
            message: str = None,
            data=None,
    ):
        self.status = status_code
        self.code = self.default_code if code is None else code
        self.message = self.default_message if message is None else message

        if data is None:
            self.data = {"msg": self.message, "code": self.code, 'data': []}
        else:
            self.data = data


def exc_handler(exc, content):
    """处理特殊异常"""

    if isinstance(exc, Http404):
        return Response({'code': 404, 'data': {}, 'msg': '数据找不到'})

    if isinstance(exc, CustomException):
        return Response(data=exc.data, status=exc.status)
    response = exception_handler(exc, content)
    if response is not None:

        # 处理 验证异常问题
        code = response.status_code
        if code == 400:
            msg = response.data
        else:
	    # 此处在msg中提示存在多个格式需要处理ErrorDetails
            msg = exc.default_detail
        return Response({'code': exc.status_code, 'data': [], 'msg': msg})
    return response

settings

REST_FRAMEWORK = {
    # 身份认证
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
    # 权限认证
    'DEFAULT_PERMISSION_CLASSES': ('utils.permissions.CustomPermission',),
    # 分页
    'DEFAULT_PAGINATION_CLASS': 'utils.pagination.CustomPagination',
    # 过滤
    'DEFAULT_FILTER_BACKENDS': (
        'django_filters.rest_framework.DjangoFilterBackend',
    ),
    # 异常
    'EXCEPTION_HANDLER': 'utils.exceptions.exc_handler'

}

pagination

分页返回格式修改(全局)。

from rest_framework.pagination import PageNumberPagination
from utils.response import CustomResponse


class CustomPagination(PageNumberPagination):
    max_page_size = 100
    page_size_query_param = 'page_size'
    page_size = 15
    
    def get_paginated_response(self, data):
      """统一分页响应格式 可以修改分页的响应参数"""
        return CustomResponse(data=OrderedDict([
            ('count', self.page.paginator.count),
            ('next', self.get_next_link()),
            ('previous', self.get_previous_link()),
            ('results', data)
        ]))


基础模型

定义公共基础model减少不必要的代码

from django.db import models


class TimeBase(models.Model):
    is_delete = models.BooleanField(default=False, null=True, blank=True, verbose_name='是否删除')
    created_at = models.DateTimeField(verbose_name='创建时间', auto_now_add=True, blank=True, null=True)
    updated_at = models.DateTimeField(verbose_name='更新时间', auto_now=True, blank=True, null=True)

    class Meta:
	# 基类
        abstract = True
        ordering = ('-created_at',)

使用时继承即可