- 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',)
使用时继承即可