调整为http相应状态

This commit is contained in:
caoqianming 2022-04-06 08:47:11 +08:00
parent d748a8dd59
commit 746c8874c4
16 changed files with 104 additions and 137 deletions

2
apps/auth1/errors.py Normal file
View File

@ -0,0 +1,2 @@
NAME_OR_PASSWORD_WRONG = '账户名或密码错误'

View File

@ -1,4 +1,5 @@
from rest_framework.exceptions import ParseError, ValidationError
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
@ -7,8 +8,9 @@ from django.contrib.auth import authenticate, login, logout
from rest_framework.generics import CreateAPIView
from rest_framework.permissions import IsAuthenticated
from apps.auth1.serializers import LoginSerializer
from apps.utils.response import FailResponse, SuccessResponse
# Create your views here.
class TokenBlackView(APIView):
@ -42,8 +44,8 @@ class LoginView(CreateAPIView):
password = vdata.get('password'))
if user is not None:
login(request, user)
return SuccessResponse()
return FailResponse(msg='账户或密码错误')
return Response()
raise ParseError('账户名或密码错误', 'username_or_password_wrong')
class LogoutView(APIView):
authentication_classes = []
@ -57,4 +59,4 @@ class LogoutView(APIView):
退出登录
"""
logout(request)
return SuccessResponse()
return Response()

View File

@ -10,7 +10,7 @@ import os
from rest_framework import serializers, status
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from apps.utils.response import SuccessResponse
from rest_framework.exceptions import NotFound
# Create your views here.
@ -47,7 +47,7 @@ class ServerInfoView(APIView):
ret['disk']['total'] = round(disk.total/1024/1024/1024, 2)
ret['disk']['used'] = round(disk.used/1024/1024/1024, 2)
ret['disk']['percent'] = disk.percent
return SuccessResponse(ret)
return Response(ret)
def get_file_list(file_path):
@ -101,7 +101,7 @@ class LogView(APIView):
"filepath": filepath,
"size": round(fsize/1000, 1)
})
return SuccessResponse(data=logs)
return Response(logs)
class LogDetailView(APIView):
@ -117,4 +117,5 @@ class LogDetailView(APIView):
data = f.read()
return Response(data)
except:
return Response('未找到', status=status.HTTP_404_NOT_FOUND)
raise NotFound('不存在该日志')

2
apps/system/errors.py Normal file
View File

@ -0,0 +1,2 @@
# 自定义的错误码
from rest_framework.exceptions import ValidationError

View File

@ -1,13 +1,10 @@
import logging
from django.conf import settings
from django.contrib.auth.hashers import check_password, make_password
from django.db import transaction
from django_celery_beat.models import (CrontabSchedule, IntervalSchedule,
PeriodicTask)
from django_celery_results.models import TaskResult
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.exceptions import ParseError, ValidationError
from rest_framework.mixins import (CreateModelMixin, DestroyModelMixin,
ListModelMixin, RetrieveModelMixin)
from rest_framework.parsers import (JSONParser,
@ -17,9 +14,9 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from apps.utils.mixins import (CustomCreateModelMixin)
from django.conf import settings
from apps.utils.permission import get_user_perms_map
from apps.utils.queryset import get_child_queryset2
from apps.utils.response import FailResponse, SuccessResponse
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
from server.celery import app as celery_app
from .filters import UserFilter
@ -32,8 +29,6 @@ from .serializers import (DeptCreateUpdateSerializer, DeptSerializer, DictCreate
UserCreateSerializer, UserListSerializer, UserPostCreateSerializer,
UserPostSerializer, UserUpdateSerializer)
logger = logging.getLogger('log')
# logger.info('请求成功! response_code:{}response_headers:{}
# response_body:{}'.format(response_code, response_headers, response_body[:251]))
@ -80,7 +75,7 @@ class PTaskViewSet(CustomModelViewSet):
obj = self.get_object()
obj.enabled = False if obj.enabled else True
obj.save()
return SuccessResponse()
return Response()
@transaction.atomic
def create(self, request, *args, **kwargs):
@ -99,7 +94,7 @@ class PTaskViewSet(CustomModelViewSet):
**interval_, defaults=interval_)
data['interval'] = interval.id
except:
raise ValidationError('时间策略有误')
raise ParseError('时间策略有误', 'schedule_wrong')
if timetype == 'crontab' and crontab_:
data['interval'] = None
try:
@ -108,11 +103,11 @@ class PTaskViewSet(CustomModelViewSet):
**crontab_, defaults=crontab_)
data['crontab'] = crontab.id
except:
raise ValidationError('时间策略有误')
raise ParseError('时间策略有误', 'schedule_wrong')
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
return SuccessResponse()
return Response()
@transaction.atomic
def update(self, request, *args, **kwargs):
@ -133,7 +128,7 @@ class PTaskViewSet(CustomModelViewSet):
**interval_, defaults=interval_)
data['interval'] = interval.id
except:
raise ValidationError('时间策略有误')
raise ParseError('时间策略有误', 'schedule_wrong')
if timetype == 'crontab' and crontab_:
data['interval'] = None
try:
@ -144,12 +139,12 @@ class PTaskViewSet(CustomModelViewSet):
**crontab_, defaults=crontab_)
data['crontab'] = crontab.id
except:
raise ValidationError('时间策略有误')
raise ParseError('时间策略有误', 'schedule_wrong')
instance = self.get_object()
serializer = self.get_serializer(instance, data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
return SuccessResponse()
return Response()
class PTaskResultViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSet):
@ -310,7 +305,7 @@ class UserViewSet(CustomModelViewSet):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save(password=password)
return SuccessResponse(data=serializer.data)
return Response(data=serializer.data)
@action(methods=['put'], detail=False, permission_classes=[IsAuthenticated])
def password(self, request, pk=None):
@ -326,11 +321,11 @@ class UserViewSet(CustomModelViewSet):
if new_password1 == new_password2:
user.set_password(new_password2)
user.save()
return SuccessResponse()
return Response()
else:
return FailResponse(msg='新密码两次输入不一致!')
raise ParseError('新密码两次输入不一致!', 'password_not_same')
else:
return FailResponse(msg='旧密码错误!')
raise ValidationError('旧密码错误!', 'old_password_wrong')
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
def info(self, request, pk=None):
@ -348,7 +343,7 @@ class UserViewSet(CustomModelViewSet):
'avatar': user.avatar,
'perms': perms,
}
return SuccessResponse(data)
return Response(data)
class FileViewSet(CustomCreateModelMixin, RetrieveModelMixin, ListModelMixin, CustomGenericViewSet):

View File

@ -1,4 +1,3 @@
from django.shortcuts import render
from apps.utils.dahua import dhClient
from apps.utils.xunxi import xxClient
from rest_framework.response import Response

46
apps/utils/exceptions.py Normal file
View File

@ -0,0 +1,46 @@
from typing import Tuple
from django.core.exceptions import PermissionDenied
from django.http import Http404
from server.settings import myLogger
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework.views import set_rollback
from django.utils.translation import gettext_lazy as _
import traceback
class MyError(exceptions.ParseError):
"""自定义业务异常
"""
def __init__(self, error:Tuple[str, str]=(), detail=None, code=None):
if error:
code, detail = error
super().__init__(detail, code)
def custom_exception_hander(exc, context):
"""
自定义异常处理
"""
if isinstance(exc, Http404):
exc = exceptions.NotFound()
elif isinstance(exc, PermissionDenied):
exc = exceptions.PermissionDenied()
if isinstance(exc, exceptions.APIException):
headers = {}
if getattr(exc, 'auth_header', None):
headers['WWW-Authenticate'] = exc.auth_header
if getattr(exc, 'wait', None):
headers['Retry-After'] = '%d' % exc.wait
if isinstance(exc.detail, (list, dict)):
data = {'err_detail':exc.detail}
data['err_codes'] = exc.get_codes()
else:
data = {'err_msg': exc.detail, 'err_code':exc.get_codes()}
set_rollback()
return Response(data, status=exc.status_code, headers=headers)
# 未处理的异常记录日志
myLogger.error(traceback.format_exc())
return Response(data={'err_code':'server_error', 'err_msg':'服务器错误'}, status=500)

View File

@ -1,8 +1,9 @@
from django.db import models
import django.utils.timezone as timezone
from django.db import models
from django.db.models.query import QuerySet
from apps.utils.snowflake import worker
from apps.utils.snowflake import idWorker
# 自定义软删除查询基类
@ -55,7 +56,7 @@ class BaseModel(models.Model):
"""
基本表
"""
id = models.CharField(max_length=20, primary_key=True, default=worker.get_id, editable=False, verbose_name='主键ID', help_text='主键ID')
id = models.CharField(max_length=20, primary_key=True, default=idWorker.get_id, editable=False, verbose_name='主键ID', help_text='主键ID')
create_time = models.DateTimeField(
default=timezone.now, verbose_name='创建时间', help_text='创建时间')
update_time = models.DateTimeField(

View File

@ -8,7 +8,7 @@ from django.db.models.query import QuerySet
def get_user_perms_map(user):
"""
获取权限列表,可用redis存取
获取权限字典,可用redis存取
"""
user_perms_map = {}
if user.is_superuser:
@ -44,7 +44,7 @@ class RbacPermission(BasePermission):
:return:
"""
if not hasattr(view, 'perms_map'):
return False
return True
user_perms_map = cache.get('perms_' + request.user.id, None)
if user_perms_map is None:
user_perms_map = get_user_perms_map(request.user)

View File

@ -1,83 +0,0 @@
import traceback
from rest_framework.renderers import JSONRenderer
from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status as drf_status
import logging
logger = logging.getLogger('log')
def custome_exception_hander(exc, context):
"""
自定义异常处理
"""
res = exception_handler(exc, context)
if res:
return res
else:
"""
日志记录
"""
logger.error(traceback.format_exc())
return None
class FitJSONRenderer(JSONRenderer):
"""
自行封装的渲染器
"""
def render(self, data, accepted_media_type=None, renderer_context=None):
"""
如果使用这个render
普通的response将会被包装成
{"code":200000,"data":"X","msg":"X"}
这样的结果
使用方法
- 全局
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': ('utils.response.FitJSONRenderer', ),
}
- 局部
class UserCountView(APIView):
renderer_classes = [FitJSONRenderer]
:param data:
:param accepted_media_type:
:param renderer_context:
:return: {"code":200,"data":"X","msg":"X"}
"""
response_body = dict(success=True, code=200000, msg='请求成功', data=None)
response = renderer_context.get("response")
status_code = response.status_code
if isinstance(data, dict) and data.keys() == response_body.keys():
response_body = data
else:
# 处理drf格式的返回数据
if status_code >= 400: # 如果http响应异常
response_body = dict(success=False, code=400000, msg='请求失败', data=None)
response_body['data'] = data # data里是详细异常信息
response_body['code'] = status_code*1000
prefix = ""
if isinstance(data, dict):
prefix = list(data.keys())[0]
data = data[prefix]
if isinstance(data, list):
data = data[0]
if prefix != 'detail':
response_body['msg'] = prefix + str(data) # 取一部分放入msg,方便前端alert
else:
response_body['data'] = data
renderer_context.get("response").status_code = 200 # 统一成200响应, 可用body里code区分业务异常
return super(FitJSONRenderer, self).render(response_body, accepted_media_type, renderer_context)
class SuccessResponse(Response):
def __init__(self, data=None, msg='请求成功', code=200000, status=None, template_name=None, headers=None, exception=False, content_type=None):
std_data = dict(success=True, code=code, msg=msg, data=data)
super().__init__(std_data, status, template_name, headers, exception, content_type)
class FailResponse(Response):
def __init__(self, msg='请求失败', data=None, code=400000, status=400, template_name=None, headers=None, exception=False, content_type=None):
std_data = dict(success=False, code=code, msg=msg, data=data)
super().__init__(std_data, status, template_name, headers, exception, content_type)

View File

@ -3,7 +3,7 @@ from rest_framework import serializers
from django_restql.mixins import DynamicFieldsMixin
class PkSerializer(serializers.Serializer):
pks = serializers.ListField(child=serializers.IntegerField(min_value=1), label="主键ID列表")
pks = serializers.ListField(child=serializers.CharField(max_length=20), label="主键ID列表")
class GenSignatureSerializer(serializers.Serializer):
path = serializers.CharField(label="图片地址")

View File

@ -2,10 +2,7 @@
# https://github.com/twitter-archive/snowflake/blob/snowflake-2010/src/main/scala/com/twitter/service/snowflake/IdWorker.scala
import time
import logging
from django.conf import settings
# logger = logging.getLogger('log')
from server.settings import SNOW_DATACENTER_ID, SNOW_WORKER_ID
class InvalidSystemClock(Exception):
"""
@ -76,7 +73,6 @@ class IdWorker(object):
# 时钟回拨
if timestamp < self.last_timestamp:
# logger.error('clock is moving backwards. Rejecting requests until {}'.format(self.last_timestamp))
raise InvalidSystemClock
if timestamp == self.last_timestamp:
@ -101,7 +97,7 @@ class IdWorker(object):
timestamp = self._gen_timestamp()
return timestamp
worker = IdWorker(settings.SNOW_DATACENTER_ID, settings.SNOW_WORKER_ID)
idWorker = IdWorker(SNOW_DATACENTER_ID, SNOW_WORKER_ID)
if __name__ == '__main__':
print(worker.get_id())
print(idWorker.get_id())

View File

@ -3,7 +3,8 @@ import os
import cv2
from server.settings import BASE_DIR
import numpy as np
from .response import FailResponse, SuccessResponse
from rest_framework.response import Response
from rest_framework.exceptions import ParseError
from apps.utils.viewsets import CustomGenericViewSet
from apps.utils.mixins import CustomCreateModelMixin
from apps.utils.serializers import GenSignatureSerializer
@ -42,6 +43,6 @@ class SignatureViewSet(CustomCreateModelMixin, CustomGenericViewSet):
ext = os.path.splitext(path)
new_path = ext[0] + '.png'
cv2.imwrite(new_path, image)
return SuccessResponse({'path': new_path.replace(BASE_DIR, '')})
return Response({'path': new_path.replace(BASE_DIR, '')})
except:
return FailResponse(msg='签名照处理失败,请重新上传')
raise ParseError('签名照处理失败,请重新上传')

View File

@ -4,9 +4,10 @@ from rest_framework.decorators import action
from apps.utils.mixins import CustomCreateModelMixin, CustomDestoryModelMixin, CustomUpdateModelMixin, OptimizationMixin
from apps.utils.permission import RbacDataMixin, RbacPermission
from apps.utils.serializers import PkSerializer
from apps.utils.response import FailResponse, SuccessResponse
from rest_framework.response import Response
from rest_framework.mixins import DestroyModelMixin, RetrieveModelMixin, ListModelMixin
from rest_framework.permissions import IsAuthenticated
from rest_framework.exceptions import ValidationError
class CustomGenericViewSet(GenericViewSet):
@ -59,9 +60,9 @@ class CustomModelViewSet(OptimizationMixin, CustomCreateModelMixin
pks = request_data.get('pks',None)
if pks:
self.get_queryset().filter(id__in=pks).delete(update_by=request.user)
return SuccessResponse()
return Response()
else:
return FailResponse(msg="未获取到pks字段")
raise ValidationError("未获取到pks字段")

View File

@ -13,7 +13,7 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
from datetime import datetime, timedelta
import os
from . import conf
from server.conf import DATABASES, XX_ENABLED, XX_LICENCE
import logging
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -164,10 +164,10 @@ REST_FRAMEWORK = {
'rest_framework.permissions.IsAuthenticated',
'apps.utils.permission.RbacPermission'
],
'DEFAULT_RENDERER_CLASSES': [
'apps.utils.response.FitJSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer'
],
# 'DEFAULT_RENDERER_CLASSES': [
# 'apps.utils.response.FitJSONRenderer',
# 'rest_framework.renderers.BrowsableAPIRenderer'
# ],
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
@ -179,7 +179,7 @@ REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
'UNAUTHENTICATED_USER': None,
'UNAUTHENTICATED_TOKEN': None,
'EXCEPTION_HANDLER': 'apps.utils.response.custome_exception_hander',
'EXCEPTION_HANDLER': 'apps.utils.exceptions.custom_exception_hander',
}
# simplejwt配置
SIMPLE_JWT = {
@ -302,6 +302,8 @@ LOGGING = {
},
}
}
# 实例化myLogger
myLogger = logging.getLogger('log')
# 大华ICC平台
DAHUA_ENABLED = conf.DAHUA_ENABLED

View File

@ -37,6 +37,7 @@ urlpatterns = [
# django后台
path('django/doc/', include('django.contrib.admindocs.urls')),
path('django/', admin.site.urls),
path('api-auth/', include('rest_framework.urls')),
# api
path('', include('apps.auth1.urls')),
@ -46,6 +47,7 @@ urlpatterns = [
path('', include('apps.third.urls')),
path('', include('apps.utils.urls')),
# api文档
path('api/docs/', include_docs_urls(title="接口文档", authentication_classes=[], permission_classes=[])),
@ -53,7 +55,7 @@ urlpatterns = [
path('api/redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
# 前端页面入口
path('',TemplateView.as_view(template_name="index.html"))
path('',TemplateView.as_view(template_name="index.html")),
] + \
static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + \
static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)