功能变化: 导出模板优化
parent
8817edd603
commit
f768cc6dea
|
@ -7,7 +7,7 @@ from rest_framework.decorators import action
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
||||||
from application import dispatch
|
from application import dispatch
|
||||||
from dvadmin.system.models import Users
|
from dvadmin.system.models import Users, Role, Dept
|
||||||
from dvadmin.system.views.role import RoleSerializer
|
from dvadmin.system.views.role import RoleSerializer
|
||||||
from dvadmin.utils.json_response import ErrorResponse, DetailResponse
|
from dvadmin.utils.json_response import ErrorResponse, DetailResponse
|
||||||
from dvadmin.utils.serializers import CustomModelSerializer
|
from dvadmin.utils.serializers import CustomModelSerializer
|
||||||
|
@ -239,11 +239,33 @@ class UserViewSet(CustomModelViewSet):
|
||||||
"name": "用户名称",
|
"name": "用户名称",
|
||||||
"email": "用户邮箱",
|
"email": "用户邮箱",
|
||||||
"mobile": "手机号码",
|
"mobile": "手机号码",
|
||||||
"gender": "用户性别(男/女/未知)",
|
"gender": {
|
||||||
"is_active": "帐号状态(启用/禁用)",
|
"title": "用户性别",
|
||||||
|
"choices": {
|
||||||
|
"data": [{"未知": 2}, {"男": 1}, {"女": 0}],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"is_active": {
|
||||||
|
"title": "帐号状态",
|
||||||
|
"choices": {
|
||||||
|
"data": [{"启用": True}, {"禁用": False}],
|
||||||
|
}
|
||||||
|
},
|
||||||
"password": "登录密码",
|
"password": "登录密码",
|
||||||
"dept": "部门ID",
|
"dept": {
|
||||||
"role": "角色ID",
|
"title": "部门",
|
||||||
|
"choices": {
|
||||||
|
"queryset": Dept.objects.filter(status=True),
|
||||||
|
"values_list": "name"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"title": "角色",
|
||||||
|
"choices": {
|
||||||
|
"queryset": Role.objects.filter(status=True),
|
||||||
|
"values_list": "name"
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
|
@action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
|
||||||
|
|
|
@ -4,7 +4,8 @@ from urllib.parse import quote
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from openpyxl import Workbook
|
from openpyxl import Workbook
|
||||||
from openpyxl.utils import get_column_letter
|
from openpyxl.worksheet.datavalidation import DataValidation
|
||||||
|
from openpyxl.utils import get_column_letter, quote_sheetname
|
||||||
from openpyxl.worksheet.table import Table, TableStyleInfo
|
from openpyxl.worksheet.table import Table, TableStyleInfo
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
|
||||||
|
@ -15,13 +16,28 @@ from dvadmin.utils.request_util import get_verbose_name
|
||||||
|
|
||||||
class ImportSerializerMixin:
|
class ImportSerializerMixin:
|
||||||
"""
|
"""
|
||||||
自定义导出模板、导入功能
|
自定义导入模板、导入功能
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 导入字段
|
# 导入字段
|
||||||
import_field_dict = {}
|
import_field_dict = {}
|
||||||
# 导入序列化器
|
# 导入序列化器
|
||||||
import_serializer_class = None
|
import_serializer_class = None
|
||||||
|
# 表格表头最大宽度,默认50个字符
|
||||||
|
export_column_width = 50
|
||||||
|
|
||||||
|
def get_string_len(self, string):
|
||||||
|
"""
|
||||||
|
获取字符串最大长度
|
||||||
|
:param string:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
length = 4
|
||||||
|
if string is None:
|
||||||
|
return length
|
||||||
|
for char in string:
|
||||||
|
length += 2.1 if ord(char) > 256 else 1
|
||||||
|
return round(length, 1) if length <= self.export_column_width else self.export_column_width
|
||||||
|
|
||||||
@transaction.atomic # Django 事务,防止出错
|
@transaction.atomic # Django 事务,防止出错
|
||||||
def import_data(self, request: Request, *args, **kwargs):
|
def import_data(self, request: Request, *args, **kwargs):
|
||||||
|
@ -44,10 +60,46 @@ class ImportSerializerMixin:
|
||||||
"Content-Disposition"
|
"Content-Disposition"
|
||||||
] = f'attachment;filename={quote(str(f"导入{get_verbose_name(queryset)}模板.xlsx"))}'
|
] = f'attachment;filename={quote(str(f"导入{get_verbose_name(queryset)}模板.xlsx"))}'
|
||||||
wb = Workbook()
|
wb = Workbook()
|
||||||
|
ws1 = wb.create_sheet("data", 1)
|
||||||
|
ws1.sheet_state = 'hidden'
|
||||||
ws = wb.active
|
ws = wb.active
|
||||||
row = get_column_letter(len(self.import_field_dict) + 1)
|
row = get_column_letter(len(self.import_field_dict) + 1)
|
||||||
column = 10
|
column = 10
|
||||||
ws.append(["序号", *self.import_field_dict.values()])
|
header_data = ["序号", ]
|
||||||
|
validation_data_dict = {}
|
||||||
|
for index, ele in enumerate(self.import_field_dict.values()):
|
||||||
|
if isinstance(ele, dict):
|
||||||
|
header_data.append(ele.get('title'))
|
||||||
|
choices = ele.get('choices', {})
|
||||||
|
if choices.get('data'):
|
||||||
|
data_list = []
|
||||||
|
for data in choices.get('data'):
|
||||||
|
data_list.extend(data.keys())
|
||||||
|
validation_data_dict[ele.get('title')] = data_list
|
||||||
|
elif choices.get('queryset') and choices.get('values_list'):
|
||||||
|
data_list = choices.get('queryset').values_list(choices.get('values_list'), flat=True)
|
||||||
|
validation_data_dict[ele.get('title')] = list(data_list)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
column_letter = get_column_letter(len(validation_data_dict))
|
||||||
|
dv = DataValidation(type="list",
|
||||||
|
formula1=f"{quote_sheetname('data')}!${column_letter}$2:${column_letter}${len(validation_data_dict[ele.get('title')]) + 1}",
|
||||||
|
allow_blank=True)
|
||||||
|
ws.add_data_validation(dv)
|
||||||
|
dv.add(f"{get_column_letter(index + 2)}2:{get_column_letter(index + 2)}1048576")
|
||||||
|
else:
|
||||||
|
header_data.append(ele)
|
||||||
|
# 添加数据列
|
||||||
|
ws1.append(list(validation_data_dict.keys()))
|
||||||
|
for index, validation_data in enumerate(validation_data_dict.values()):
|
||||||
|
for inx, ele in enumerate(validation_data):
|
||||||
|
ws1[f"{get_column_letter(index + 1)}{inx + 2}"] = ele
|
||||||
|
# 插入导出模板正式数据
|
||||||
|
df_len_max = [self.get_string_len(ele) for ele in header_data]
|
||||||
|
ws.append(header_data)
|
||||||
|
# 更新列宽
|
||||||
|
for index, width in enumerate(df_len_max):
|
||||||
|
ws.column_dimensions[get_column_letter(index + 1)].width = width
|
||||||
tab = Table(displayName="Table1", ref=f"A1:{row}{column}") # 名称管理器
|
tab = Table(displayName="Table1", ref=f"A1:{row}{column}") # 名称管理器
|
||||||
style = TableStyleInfo(
|
style = TableStyleInfo(
|
||||||
name="TableStyleLight11",
|
name="TableStyleLight11",
|
||||||
|
|
Loading…
Reference in New Issue