From f768cc6deafde5dd0efd407f704f2e6efc44f9dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BC=BA?= <1206709430@qq.com> Date: Tue, 14 Jun 2022 22:59:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8F=98=E5=8C=96:=20?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E6=A8=A1=E6=9D=BF=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/system/views/user.py | 36 +++++++++--- backend/dvadmin/utils/import_export_mixin.py | 58 +++++++++++++++++++- 2 files changed, 84 insertions(+), 10 deletions(-) diff --git a/backend/dvadmin/system/views/user.py b/backend/dvadmin/system/views/user.py index 4ef20fd..771270d 100644 --- a/backend/dvadmin/system/views/user.py +++ b/backend/dvadmin/system/views/user.py @@ -7,7 +7,7 @@ from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated 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.utils.json_response import ErrorResponse, DetailResponse from dvadmin.utils.serializers import CustomModelSerializer @@ -19,7 +19,7 @@ class UserSerializer(CustomModelSerializer): """ 用户管理-序列化器 """ - dept_name = serializers.CharField(source='dept.name',read_only=True) + dept_name = serializers.CharField(source='dept.name', read_only=True) role_info = DynamicSerializerMethodField() class Meta: @@ -30,7 +30,7 @@ class UserSerializer(CustomModelSerializer): "post": {"required": False}, } - def get_role_info(self, instance,parsed_query): + def get_role_info(self, instance, parsed_query): roles = instance.role.all() # You can do what ever you want in here @@ -239,11 +239,33 @@ class UserViewSet(CustomModelViewSet): "name": "用户名称", "email": "用户邮箱", "mobile": "手机号码", - "gender": "用户性别(男/女/未知)", - "is_active": "帐号状态(启用/禁用)", + "gender": { + "title": "用户性别", + "choices": { + "data": [{"未知": 2}, {"男": 1}, {"女": 0}], + } + }, + "is_active": { + "title": "帐号状态", + "choices": { + "data": [{"启用": True}, {"禁用": False}], + } + }, "password": "登录密码", - "dept": "部门ID", - "role": "角色ID", + "dept": { + "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]) diff --git a/backend/dvadmin/utils/import_export_mixin.py b/backend/dvadmin/utils/import_export_mixin.py index 98f221b..1b60318 100644 --- a/backend/dvadmin/utils/import_export_mixin.py +++ b/backend/dvadmin/utils/import_export_mixin.py @@ -4,7 +4,8 @@ from urllib.parse import quote from django.db import transaction from django.http import HttpResponse 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 rest_framework.request import Request @@ -15,13 +16,28 @@ from dvadmin.utils.request_util import get_verbose_name class ImportSerializerMixin: """ - 自定义导出模板、导入功能 + 自定义导入模板、导入功能 """ # 导入字段 import_field_dict = {} # 导入序列化器 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 事务,防止出错 def import_data(self, request: Request, *args, **kwargs): @@ -44,10 +60,46 @@ class ImportSerializerMixin: "Content-Disposition" ] = f'attachment;filename={quote(str(f"导入{get_verbose_name(queryset)}模板.xlsx"))}' wb = Workbook() + ws1 = wb.create_sheet("data", 1) + ws1.sheet_state = 'hidden' ws = wb.active row = get_column_letter(len(self.import_field_dict) + 1) 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}") # 名称管理器 style = TableStyleInfo( name="TableStyleLight11",