diff --git a/backend/application/__init__.py b/backend/application/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9e0d95fd74b8a0e80d88f65f97ceda4423a7125e 100644 --- a/backend/application/__init__.py +++ b/backend/application/__init__.py @@ -0,0 +1,3 @@ +from .celery import app as celery_app + +__all__ = ('celery_app',) \ No newline at end of file diff --git a/backend/application/celery.py b/backend/application/celery.py index d57b92ada7e3cc3c2e569a9b549d1ea2c52c2b31..10bce56c5f643ba19c776409ee2d5482e2fc3560 100644 --- a/backend/application/celery.py +++ b/backend/application/celery.py @@ -15,7 +15,7 @@ else: from celery import Celery app = Celery(f"application") -app.config_from_object('django.conf:settings') +app.config_from_object('django.conf:settings', namespace='CELERY') app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) platforms.C_FORCE_ROOT = True diff --git a/backend/dvadmin/utils/import_export_mixin.py b/backend/dvadmin/utils/import_export_mixin.py index 44f51cc5841ea7a56cbe9c3de75d7cc812c7abfe..839248380e1f6554f960eb7d1d7bb1d99f50a676 100644 --- a/backend/dvadmin/utils/import_export_mixin.py +++ b/backend/dvadmin/utils/import_export_mixin.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from urllib.parse import quote +from celery import shared_task from django.db import transaction from django.http import HttpResponse from openpyxl import Workbook @@ -27,7 +28,7 @@ class ImportSerializerMixin: # 表格表头最大宽度,默认50个字符 export_column_width = 50 - def is_number(self,num): + def is_number(self, num): try: float(num) return True @@ -57,7 +58,38 @@ class ImportSerializerMixin: length += 2.1 if ord(char) > 256 else 1 return round(length, 1) if length <= self.export_column_width else self.export_column_width - @action(methods=['get','post'],detail=False) + @staticmethod + @shared_task + def async_import_data(import_func, file_url, table_model, import_serializer, import_field_dict): + """ + 异步导入数据 + """ + import_func(file_url, table_model, import_serializer, import_field_dict) + + @staticmethod + def synch_import_data(file_url, table_model, import_serializer, import_field_dict): + """ + 同步导入数据 + """ + # # 从excel中组织对应的数据结构,然后使用序列化器保存 + queryset = table_model.objects.all() + # 获取多对多字段 + m2m_fields = [ + ele.name + for ele in queryset.model._meta.get_fields() + if hasattr(ele, "many_to_many") and ele.many_to_many == True + ] + import_field_dict = {'id': '更新主键(勿改)', **import_field_dict} + data = import_to_data(file_url, import_field_dict, m2m_fields) + for ele in data: + filter_dic = {'id': ele.get('id')} + instance = filter_dic and queryset.filter(**filter_dic).first() + serializer = import_serializer(instance, data=ele) + serializer.is_valid(raise_exception=True) + serializer.save() + return {'msg': '导入成功!'} + + @action(methods=['get', 'post'], detail=False) @transaction.atomic # Django 事务,防止出错 def import_data(self, request: Request, *args, **kwargs): """ @@ -135,27 +167,22 @@ class ImportSerializerMixin: wb.save(response) return response else: - # 从excel中组织对应的数据结构,然后使用序列化器保存 - queryset = self.filter_queryset(self.get_queryset()) - # 获取多对多字段 - m2m_fields = [ - ele.name - for ele in queryset.model._meta.get_fields() - if hasattr(ele, "many_to_many") and ele.many_to_many == True - ] - import_field_dict = {'id':'更新主键(勿改)',**self.import_field_dict} - data = import_to_data(request.data.get("url"), import_field_dict, m2m_fields) - for ele in data: - filter_dic = {'id':ele.get('id')} - instance = filter_dic and queryset.filter(**filter_dic).first() - # print(156,ele) - serializer = self.import_serializer_class(instance, data=ele, request=request) - serializer.is_valid(raise_exception=True) - serializer.save() - return DetailResponse(msg=f"导入成功!") + async_import = request.data.get("async_import") + kwargs = { + "file_url": request.data.get("url"), + "table_model": self.queryset.model, + "import_serializer": self.import_serializer_class, + "import_field_dict": self.import_field_dict + } + if async_import: + self.async_import_data.delay(self.synch_import_data, **kwargs) + return DetailResponse(msg=f"异步导入数据,请等待。。") + else: + self.synch_import_data(**kwargs) + return DetailResponse(msg=f"同步导入数据,已完成。。。") - @action(methods=['get'],detail=False) - def update_template(self,request): + @action(methods=['get'], detail=False) + def update_template(self, request): queryset = self.filter_queryset(self.get_queryset()) assert self.import_field_dict, "'%s' 请配置对应的导入模板字段。" % self.__class__.__name__ assert self.import_serializer_class, "'%s' 请配置对应的导入序列化器。" % self.__class__.__name__ @@ -169,9 +196,9 @@ class ImportSerializerMixin: ws1.sheet_state = "hidden" ws = wb.active import_field_dict = {} - header_data = ["序号","更新主键(勿改)"] - hidden_header = ["#","id"] - #----设置选项---- + header_data = ["序号", "更新主键(勿改)"] + hidden_header = ["#", "id"] + # ----设置选项---- validation_data_dict = {} for index, item in enumerate(self.import_field_dict.items()): items = list(item) @@ -206,7 +233,7 @@ class ImportSerializerMixin: 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] row = get_column_letter(len(hidden_header) + 1) column = 1 @@ -218,16 +245,16 @@ class ImportSerializerMixin: if key == h_item: if val is None or val == "": results_list.append("") - elif isinstance(val,list): + elif isinstance(val, list): results_list.append(str(val)) else: results_list.append(val) # 计算最大列宽度 - if isinstance(val,str): + if isinstance(val, str): result_column_width = self.get_string_len(val) if h_index != 0 and result_column_width > df_len_max[h_index]: df_len_max[h_index] = result_column_width - ws.append([index+1,*results_list]) + ws.append([index + 1, *results_list]) column += 1 #  更新列宽 for index, width in enumerate(df_len_max): @@ -258,7 +285,7 @@ class ExportSerializerMixin: # 表格表头最大宽度,默认50个字符 export_column_width = 50 - def is_number(self,num): + def is_number(self, num): try: float(num) return True @@ -288,7 +315,7 @@ class ExportSerializerMixin: length += 2.1 if ord(char) > 256 else 1 return round(length, 1) if length <= self.export_column_width else self.export_column_width - @action(methods=['get'],detail=False) + @action(methods=['get'], detail=False) def export_data(self, request: Request, *args, **kwargs): """ 导出功能 @@ -316,15 +343,15 @@ class ExportSerializerMixin: for index, results in enumerate(data): results_list = [] for h_index, h_item in enumerate(hidden_header): - for key,val in results.items(): + for key, val in results.items(): if key == h_item: - if val is None or val=="": + if val is None or val == "": results_list.append("") else: results_list.append(val) # 计算最大列宽度 result_column_width = self.get_string_len(val) - if h_index !=0 and result_column_width > df_len_max[h_index]: + if h_index != 0 and result_column_width > df_len_max[h_index]: df_len_max[h_index] = result_column_width ws.append([index + 1, *results_list]) column += 1 diff --git a/backend/requirements.txt b/backend/requirements.txt index 2e7c6cb6131855497d1be97d0b97f21a4e6eea7c..8c34a6c9113289e673ddc3d27998b2d59908782e 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -28,5 +28,4 @@ uvicorn==0.23.2 gunicorn==21.2.0 gevent==23.9.1 Pillow==10.1.0 -dvadmin-celery==1.0.5 pyinstaller==6.8.0 \ No newline at end of file