优化部分接口查询、n+1问题, 添加logs
This commit is contained in:
@@ -23,7 +23,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
SECRET_KEY = 'django-insecure-m4@pv814c_m^pgpyhz^i96a@mcqh_@m9ccu(17*895t!79e!nb'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = os.getenv('DEBUG', 'False') == 'True'
|
||||
DEBUG = os.getenv('DEBUG', 'True') == 'True'
|
||||
|
||||
# 演示环境配置
|
||||
DEMO_MODE = os.getenv('DEMO_MODE', 'False') == 'False'
|
||||
@@ -208,5 +208,27 @@ CELERY_BEAT_SCHEDULE = {
|
||||
}
|
||||
# celery 配置结束
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'filters': {
|
||||
'ignore_auth_user': {
|
||||
'()': 'utils.filters_logs.IgnoreSQLFilter',
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
'filters': ['ignore_auth_user'],
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django.db.backends': {
|
||||
'handlers': ['console'],
|
||||
'level': 'DEBUG', # 只在 DEBUG 模式时生效
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if os.path.exists(os.path.join(BASE_DIR, 'backend/local_settings.py')):
|
||||
from backend.local_settings import *
|
||||
@@ -1,10 +1,11 @@
|
||||
from collections import defaultdict
|
||||
from datetime import timezone, datetime
|
||||
|
||||
from django.db import models
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import status, serializers
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.filters import SearchFilter, OrderingFilter
|
||||
from rest_framework.response import Response
|
||||
|
||||
from system.models import Dept
|
||||
from utils.custom_model_viewSet import CustomModelViewSet
|
||||
@@ -23,9 +24,9 @@ class DeptSerializer(CustomModelSerializer):
|
||||
|
||||
def get_children(self, obj):
|
||||
"""获取子部门"""
|
||||
children = obj.children.all().order_by('id')
|
||||
children = getattr(obj, 'children', [])
|
||||
if children:
|
||||
return DeptSerializer(children, many=True).data
|
||||
return DeptSerializer(children.all(), many=True).data
|
||||
return []
|
||||
|
||||
def get_status_text(self, obj):
|
||||
@@ -35,7 +36,9 @@ class DeptSerializer(CustomModelSerializer):
|
||||
|
||||
class DeptViewSet(CustomModelViewSet):
|
||||
"""部门管理视图集"""
|
||||
queryset = Dept.objects.filter(pid__isnull=True).order_by('id', 'status')
|
||||
queryset = Dept.objects.filter(pid__isnull=True).order_by('id', 'status').select_related('pid').prefetch_related(
|
||||
models.Prefetch('children', queryset=Dept.objects.order_by('id'))
|
||||
)
|
||||
serializer_class = DeptSerializer
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['status', 'pid']
|
||||
@@ -78,8 +81,39 @@ class DeptViewSet(CustomModelViewSet):
|
||||
|
||||
@action(detail=False, methods=['get'])
|
||||
def tree(self, request):
|
||||
"""获取部门树形结构"""
|
||||
queryset = self.get_queryset().filter(pid__isnull=True)
|
||||
serializer = self.get_serializer(queryset, many=True)
|
||||
return Response(serializer.data)
|
||||
"""一次性查出所有部门,构建树形结构"""
|
||||
all_depts = Dept.objects.all().order_by('sort', 'id')
|
||||
dept_dict = {}
|
||||
children_map = defaultdict(list)
|
||||
|
||||
# 先序列化为 dict,不递归
|
||||
for dept in all_depts:
|
||||
item = {
|
||||
'id': dept.id,
|
||||
'pid': dept.pid_id,
|
||||
'name': dept.name,
|
||||
'status': dept.status,
|
||||
'status_text': dept.get_status_display(),
|
||||
'create_time': dept.create_time,
|
||||
'sort': dept.sort,
|
||||
'leader': dept.leader,
|
||||
'phone': dept.phone,
|
||||
'email': dept.email,
|
||||
'remark': dept.remark,
|
||||
'children': [],
|
||||
}
|
||||
dept_dict[dept.id] = item
|
||||
if dept.pid_id:
|
||||
children_map[dept.pid_id].append(item)
|
||||
|
||||
# 构建树
|
||||
for dept_id, dept in dept_dict.items():
|
||||
dept['children'] = children_map.get(dept_id, [])
|
||||
|
||||
# 返回 pid=None(根部门)
|
||||
tree = [dept for dept in dept_dict.values() if dept['pid'] is None]
|
||||
return self._build_response(
|
||||
data=tree,
|
||||
message="ok",
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
@@ -91,7 +91,7 @@ class MenuMetaViewSet(viewsets.ModelViewSet):
|
||||
|
||||
class MenuViewSet(CustomModelViewSet):
|
||||
"""菜单管理视图集"""
|
||||
queryset = Menu.objects.filter(pid__isnull=True).order_by('sort', 'id', 'status')
|
||||
queryset = Menu.objects.filter(pid__isnull=True).order_by('sort', 'id', 'status').prefetch_related('children')
|
||||
serializer_class = MenuSerializer
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['status', 'type', 'pid', 'name']
|
||||
|
||||
@@ -42,7 +42,7 @@ class RoleFilter(filters.FilterSet):
|
||||
|
||||
class RoleViewSet(CustomModelViewSet):
|
||||
"""角色管理视图集"""
|
||||
queryset = Role.objects.all()
|
||||
queryset = Role.objects.all().prefetch_related('permissions')
|
||||
serializer_class = RoleSerializer
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_class = RoleFilter
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from django.db.models import Prefetch, F
|
||||
from django.utils import timezone
|
||||
from rest_framework import serializers
|
||||
from rest_framework.authtoken.models import Token
|
||||
@@ -152,7 +153,7 @@ class UserViewSet(CustomModelViewSet):
|
||||
"""
|
||||
用户数据 视图集
|
||||
"""
|
||||
queryset = User.objects.filter(is_deleted=False).order_by('-id')
|
||||
queryset = User.objects.filter(is_deleted=False).order_by('-id').prefetch_related('role', 'dept', 'post')
|
||||
serializer_class = UserSerializer
|
||||
read_only_fields = ['id', 'create_time', 'update_time', 'login_ip']
|
||||
filterset_class = UserFilter
|
||||
|
||||
19
backend/utils/filters_logs.py
Normal file
19
backend/utils/filters_logs.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import logging
|
||||
|
||||
class IgnoreSQLFilter(logging.Filter):
|
||||
def __init__(self, name=''):
|
||||
super().__init__(name)
|
||||
# 后续只要在这里添加关键字即可
|
||||
self.ignore_keywords = [
|
||||
'authtoken_token',
|
||||
'@@lower_case_table_names',
|
||||
'SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
||||
]
|
||||
|
||||
def filter(self, record):
|
||||
sql = record.getMessage().strip().lower()
|
||||
# 如果包含任何一个关键字,则返回 False(不打印)
|
||||
for keyword in self.ignore_keywords:
|
||||
if keyword.lower() in sql:
|
||||
return False
|
||||
return True
|
||||
@@ -53,4 +53,11 @@ async function deleteDept(id: string) {
|
||||
return requestClient.delete(`/system/dept/${id}/`);
|
||||
}
|
||||
|
||||
export { createDept, deleteDept, getDeptList, updateDept };
|
||||
/**
|
||||
* 查询tree
|
||||
*/
|
||||
async function treeDept() {
|
||||
return requestClient.get(`/system/dept/tree/`);
|
||||
}
|
||||
|
||||
export { createDept, deleteDept, getDeptList, treeDept, updateDept };
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Plus } from '@vben/icons';
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { deleteDept, getDeptList } from '#/api/system/dept';
|
||||
import { deleteDept, treeDept } from '#/api/system/dept';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { useColumns } from './data';
|
||||
@@ -108,7 +108,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async (_params) => {
|
||||
return await getDeptList();
|
||||
return await treeDept();
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user