日常修复内容

This commit is contained in:
2026-04-20 18:00:55 +08:00
parent 518f2f43a7
commit dffc1d5872
188 changed files with 3969 additions and 3175 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,212 +1,216 @@
from copy import deepcopy from copy import deepcopy
from pathlib import Path from pathlib import Path
from ninja_extra import api_controller, ControllerBase, route from ninja_extra import api_controller, ControllerBase, route
from ninja_extra.permissions import IsAuthenticated from ninja_extra.permissions import IsAuthenticated
from ninja_jwt.authentication import JWTAuth from ninja_jwt.authentication import JWTAuth
from django.db import transaction from django.db import transaction
from django.db.models import QuerySet from django.db.models import QuerySet
from docxtpl import DocxTemplate from docxtpl import DocxTemplate
from apps.dict.models import Dict from apps.dict.models import Dict
from utils.chen_response import ChenResponse from utils.chen_response import ChenResponse
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from typing import Union from typing import Union
from docxtpl import InlineImage from docxtpl import InlineImage
from apps.project.models import Dut, Project, Round from apps.project.models import Dut, Project, Round
from utils.util import get_list_dict, get_str_dict, get_ident, get_case_ident from utils.util import get_list_dict, get_str_dict, get_ident, get_case_ident
from utils.chapter_tools.csx_chapter import create_csx_chapter_dict from utils.chapter_tools.csx_chapter import create_csx_chapter_dict
from utils.path_utils import project_path from utils.path_utils import project_path
from apps.createDocument.extensions.util import delete_dir_files from apps.createDocument.extensions.util import delete_dir_files
from apps.createDocument.extensions.parse_rich_text import RichParser from apps.createDocument.extensions.parse_rich_text import RichParser
# 导入生成日志记录模块 # 导入生成日志记录模块
from apps.createSeiTaiDocument.extensions.logger import GenerateLogger from apps.createSeiTaiDocument.extensions.logger import GenerateLogger
chinese_round_name: list = ['', '', '', '', '', '', '', '', '', ''] chinese_round_name: list = ['', '', '', '', '', '', '', '', '', '']
# @api_controller("/generateHSM", tags=['生成回归记录系列文档'], auth=JWTAuth(), permissions=[IsAuthenticated]) # @api_controller("/generateHSM", tags=['生成回归记录系列文档'], auth=JWTAuth(), permissions=[IsAuthenticated])
@api_controller("/generateHJL", tags=['生成回归记录系列文档']) @api_controller("/generateHJL", tags=['生成回归记录系列文档'])
class GenerateControllerHJL(ControllerBase): class GenerateControllerHJL(ControllerBase):
logger = GenerateLogger('回归测试记录') logger = GenerateLogger('回归测试记录')
# important删除之前的文件 # important删除之前的文件
@route.get('/create/deleteHJLDocument', url_name='delete-hjl-document') @route.get('/create/deleteHJLDocument', url_name='delete-hjl-document')
def delete_hjl_document(self, id: int): def delete_hjl_document(self, id: int):
project_path_str = project_path(id) project_path_str = project_path(id)
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl' save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl'
delete_dir_files(save_path) delete_dir_files(save_path)
@route.get("/create/basicInformation", url_name="create-basicInformation") @route.get("/create/basicInformation", url_name="create-basicInformation")
@transaction.atomic @transaction.atomic
def create_basicInformation(self, id: int): def create_basicInformation(self, id: int):
"""生成回归测试记录的被测软件基本信息""" """生成回归测试记录的被测软件基本信息"""
project_path_str = project_path(id) project_path_str = project_path(id)
tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/hjl' / '被测软件基本信息.docx' tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/hjl' / '被测软件基本信息.docx'
doc = DocxTemplate(tpl_path) doc = DocxTemplate(tpl_path)
project_obj = get_object_or_404(Project, id=id) project_obj = get_object_or_404(Project, id=id)
# 第一轮次对象 # 第一轮次对象
round1_obj: Union[Round, None] = project_obj.pField.filter(key='0').first() round1_obj: Union[Round, None] = project_obj.pField.filter(key='0').first()
# 第一轮源代码被测件对象 # 第一轮源代码被测件对象
round1_so_dut: Union[Dut, None] = round1_obj.rdField.filter(type='SO').first() round1_so_dut: Union[Dut, None] = round1_obj.rdField.filter(type='SO').first()
languages = get_list_dict('language', project_obj.language) languages = get_list_dict('language', project_obj.language)
language_list = [item['ident_version'] for item in languages] language_list = [item['ident_version'] for item in languages]
# 取非第一轮次 runtimes = get_list_dict('runtime', project_obj.runtime)
hround_list: QuerySet = project_obj.pField.exclude(key='0') runtime_list = [item['ident_version'] for item in runtimes]
if len(hround_list) < 1: devplants = get_list_dict('devplant', project_obj.devplant)
# ***Inspect-start*** devplant_list = [item['ident_version'] for item in devplants]
self.logger.model = '回归测试记录' # 取非第一轮次
self.logger.write_warning_log('当前文档全部片段', f'该项目没有创建轮次') hround_list: QuerySet = project_obj.pField.exclude(key='0')
# ***Inspect-end*** if len(hround_list) < 1:
return ChenResponse(code=400, status=400, message='您未创建轮次,请创建完毕后再试') # ***Inspect-start***
self.logger.model = '回归测试记录'
context = { self.logger.write_warning_log('当前文档全部片段', f'该项目没有创建轮次')
'project_name': project_obj.name, # ***Inspect-end***
'language': "".join(language_list), return ChenResponse(code=400, status=400, message='您未创建轮次,请创建完毕后再试')
'soft_type': project_obj.get_soft_type_display(),
'security_level': get_str_dict(project_obj.security_level, 'security_level'), context = {
'runtime': get_str_dict(project_obj.runtime, 'runtime'), 'project_name': project_obj.name,
'devplant': get_str_dict(project_obj.devplant, 'devplant'), 'language': "".join(language_list),
'recv_date': project_obj.beginTime.strftime("%Y-%m-%d"), 'soft_type': project_obj.get_soft_type_display(),
'dev_unit': project_obj.dev_unit, 'security_level': get_str_dict(project_obj.security_level, 'security_level'),
} 'runtime': "".join(runtime_list),
'devplant': "".join(devplant_list),
version_info = [{'version': round1_so_dut.version, 'recv_date': project_obj.beginTime.strftime("%Y-%m-%d"),
'line_count': int(round1_so_dut.total_lines), 'dev_unit': project_obj.dev_unit,
'effective_line': int(round1_so_dut.effective_lines)}] }
# 循环回归的轮次
for hround in hround_list: version_info = [{'version': round1_so_dut.version,
# 每个轮次独立渲染context 'line_count': int(round1_so_dut.total_lines),
context_round = deepcopy(context) 'effective_line': int(round1_so_dut.effective_lines)}]
# 取中文名称 # 循环回归的轮次
cname = chinese_round_name[int(hround.key)] # 输出二、三... for hround in hround_list:
# 取该轮次源代码版本放入版本列表 # 每个轮次独立渲染context
so_dut: Dut = hround.rdField.filter(type='SO').first() context_round = deepcopy(context)
if not so_dut: # 取中文名称
return ChenResponse(code=400, status=400, message=f'您第{cname}轮次中缺少源代码被测件,请添加') cname = chinese_round_name[int(hround.key)] # 输出二、三...
version_info.append( # 取该轮次源代码版本放入版本列表
{'version': so_dut.version, 'line_count': int(so_dut.total_lines), so_dut: Dut = hround.rdField.filter(type='SO').first()
'effective_line': int(so_dut.effective_lines)}) if not so_dut:
context_round['version_info'] = version_info return ChenResponse(code=400, status=400, message=f'您第{cname}轮次中缺少源代码被测件,请添加')
# 开始渲染每个轮次的二级文档 version_info.append(
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl' / f"{cname}轮被测软件基本信息.docx" {'version': so_dut.version, 'line_count': int(so_dut.total_lines),
doc.render(context=context_round, autoescape=True) 'effective_line': int(so_dut.effective_lines)})
try: context_round['version_info'] = version_info
doc.save(save_path) # 开始渲染每个轮次的二级文档
except PermissionError: save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl' / f"{cname}轮被测软件基本信息.docx"
return ChenResponse(code=400, status=400, message='您打开了生成的文档,请关闭后重试') doc.render(context=context_round, autoescape=True)
return ChenResponse(code=200, status=200, message='多轮回归说明文档基本信息生成完毕') try:
doc.save(save_path)
@route.get("/create/caseinfo", url_name="create-caseinfo") except PermissionError:
@transaction.atomic return ChenResponse(code=400, status=400, message='您打开了生成的文档,请关闭后重试')
def create_caseinfo(self, id: int): return ChenResponse(code=200, status=200, message='多轮回归说明文档基本信息生成完毕')
"""生成回归测试记录的-{测试用例记录}"""
project_path_str = project_path(id) @route.get("/create/caseinfo", url_name="create-caseinfo")
tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/hjl' / '测试用例记录.docx' @transaction.atomic
doc = DocxTemplate(tpl_path) def create_caseinfo(self, id: int):
project_obj = get_object_or_404(Project, id=id) """生成回归测试记录的-{测试用例记录}"""
hround_list: QuerySet = project_obj.pField.exclude(key='0') project_path_str = project_path(id)
if len(hround_list) < 1: tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/hjl' / '测试用例记录.docx'
return None doc = DocxTemplate(tpl_path)
demand_prefix = '3.1' project_obj = get_object_or_404(Project, id=id)
# 循环每轮轮次对象 hround_list: QuerySet = project_obj.pField.exclude(key='0')
for hround in hround_list: if len(hround_list) < 1:
cname = chinese_round_name[int(hround.key)] # var输出二、三字样 return None
test_type_len = Dict.objects.get(code='testType').dictItem.count() # 测试类型的个数 demand_prefix = '3.1'
type_number_list = [i for i in range(1, test_type_len + 1)] # 测试类型编号对应的列表 # 循环每轮轮次对象
list_list = [[] for j in range(1, test_type_len + 1)] # 每个测试类型组合为一个列表[[],[],[],[]] for hround in hround_list:
testType_list, last_chapter_items = create_csx_chapter_dict(hround) cname = chinese_round_name[int(hround.key)] # var输出二、三字样
testDemands = hround.rtField.all() # 本轮所有测试项 test_type_len = Dict.objects.get(code='testType').dictItem.count() # 测试类型的个数
for demand in testDemands: type_number_list = [i for i in range(1, test_type_len + 1)] # 测试类型编号对应的列表
type_index = type_number_list.index(int(demand.testType)) list_list = [[] for j in range(1, test_type_len + 1)] # 每个测试类型组合为一个列表[[],[],[],[]]
demand_ident = get_ident(demand) testType_list, last_chapter_items = create_csx_chapter_dict(hround)
# ~~~组装测试项~~~ testDemands = hround.rtField.all() # 本轮所有测试项
demand_last_chapter = last_chapter_items[demand.testType].index(demand.key) + 1 for demand in testDemands:
demand_chapter = ".".join([demand_prefix, str(testType_list.index(demand.testType) + 1), type_index = type_number_list.index(int(demand.testType))
str(demand_last_chapter)]) demand_ident = get_ident(demand)
demand_dict = { # ~~~组装测试项~~~
'name': demand.name, demand_last_chapter = last_chapter_items[demand.testType].index(demand.key) + 1
'ident': demand_ident, demand_chapter = ".".join([demand_prefix, str(testType_list.index(demand.testType) + 1),
'chapter': demand_chapter, str(demand_last_chapter)])
'item': [] demand_dict = {
} 'name': demand.name,
# ~~~这里组装测试项里面的测试用例~~~ 'ident': demand_ident,
for case in demand.tcField.all(): 'chapter': demand_chapter,
step_list = [] 'item': []
index = 1 }
for one in case.step.all(): # ~~~这里组装测试项里面的测试用例~~~
# 这里需要对operation富文本处理 for case in demand.tcField.all():
rich_parser = RichParser(one.operation) step_list = []
desc_list = rich_parser.get_final_list(doc, img_size=68) index = 1
rich_parser2 = RichParser(one.result) for one in case.step.all():
res_list = rich_parser2.get_final_list(doc, img_size=75) # 这里需要对operation富文本处理
# 组装用例里面的步骤dict rich_parser = RichParser(one.operation)
passed = '通过' desc_list = rich_parser.get_final_list(doc, img_size=68)
if one.passed == '2': rich_parser2 = RichParser(one.result)
passed = '未通过' res_list = rich_parser2.get_final_list(doc, img_size=75)
if one.passed == '3': # 组装用例里面的步骤dict
passed = '未执行' passed = '通过'
step_dict = { if one.passed == '2':
'index': index, passed = '未通过'
'operation': desc_list, if one.passed == '3':
'expect': one.expect, passed = '未执行'
'result': res_list, step_dict = {
'passed': passed, 'index': index,
} 'operation': desc_list,
step_list.append(step_dict) 'expect': one.expect,
index += 1 'result': res_list,
# 查询所有的problem 'passed': passed,
problem_list = [] }
problem_prefix = "PT" step_list.append(step_dict)
proj_ident = project_obj.ident index += 1
for problem in case.caseField.all(): # 查询所有的problem
problem_list.append("_".join([problem_prefix, proj_ident, problem.ident])) problem_list = []
# fpga的时序图 problem_prefix = "PT"
rich_parser3 = RichParser(case.timing_diagram) proj_ident = project_obj.ident
timing_diagram = rich_parser3.get_final_list(doc, img_size=115, height=50) for problem in case.caseField.all():
has_timing_diagram = False problem_list.append("_".join([problem_prefix, proj_ident, problem.ident]))
if len(timing_diagram) > 0: # fpga的时序图
if isinstance(timing_diagram[0], InlineImage): rich_parser3 = RichParser(case.timing_diagram)
has_timing_diagram = True timing_diagram = rich_parser3.get_final_list(doc, img_size=115, height=50)
# 组装用例的dict has_timing_diagram = False
case_dict = { if len(timing_diagram) > 0:
'name': case.name, if isinstance(timing_diagram[0], InlineImage):
'ident': get_case_ident(demand_ident, case), has_timing_diagram = True
'summary': case.summarize, # 组装用例的dict
'initialization': case.initialization, case_dict = {
'premise': case.premise, 'name': case.name,
'design_person': case.designPerson, 'ident': get_case_ident(demand_ident, case),
'test_person': case.testPerson, 'summary': case.summarize,
'monitor_person': case.monitorPerson, 'initialization': case.initialization,
'step': step_list, 'premise': case.premise,
'time': str(case.exe_time) if case.exe_time is not None else str(case.update_datetime), 'design_person': case.designPerson,
'problems': "".join(problem_list), 'test_person': case.testPerson,
'round_num_chn': cname, 'monitor_person': case.monitorPerson,
# 2025年4月24日新增 'step': step_list,
'has_timing_diagram': has_timing_diagram, 'time': str(case.exe_time) if case.exe_time is not None else str(case.update_datetime),
'timing_diagram': timing_diagram, 'problems': "".join(problem_list),
} 'round_num_chn': cname,
demand_dict['item'].append(case_dict) # 2025年4月24日新增
'has_timing_diagram': has_timing_diagram,
list_list[type_index].append(demand_dict) 'timing_diagram': timing_diagram,
# 定义渲染上下文 }
context = {} demand_dict['item'].append(case_dict)
output_list = []
for (index, li) in enumerate(list_list): list_list[type_index].append(demand_dict)
qs = Dict.objects.get(code="testType").dictItem.get(key=str(index + 1)) # 定义渲染上下文
context_str = qs.title context = {}
sort = qs.sort output_list = []
table = { for (index, li) in enumerate(list_list):
"type": context_str, qs = Dict.objects.get(code="testType").dictItem.get(key=str(index + 1))
"item": li, context_str = qs.title
"sort": sort sort = qs.sort
} table = {
output_list.append(table) "type": context_str,
# 排序 "item": li,
output_list = sorted(output_list, key=(lambda x: x["sort"])) "sort": sort
context["data"] = output_list }
# 最后渲染 output_list.append(table)
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl' / f"{cname}轮测试用例记录.docx" # 排序
doc.render(context, autoescape=True) output_list = sorted(output_list, key=(lambda x: x["sort"]))
try: context["data"] = output_list
doc.save(save_path) # 最后渲染
except PermissionError: save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl' / f"{cname}轮测试用例记录.docx"
return ChenResponse(code=400, status=400, message='您打开了生成的文档,请关闭后重试') doc.render(context, autoescape=True)
return ChenResponse(code=200, status=200, message='多轮回归测试用例记录生成完毕') try:
doc.save(save_path)
except PermissionError:
return ChenResponse(code=400, status=400, message='您打开了生成的文档,请关闭后重试')
return ChenResponse(code=200, status=200, message='多轮回归测试用例记录生成完毕')

File diff suppressed because it is too large Load Diff

View File

@@ -1,155 +1,155 @@
# 导入内置模块 # 导入内置模块
from pathlib import Path from pathlib import Path
# 导入django、ninja等模块 from django.db.models import QuerySet
from ninja_extra import api_controller, ControllerBase, route # 导入django、ninja等模块
from django.db import transaction from ninja_extra import api_controller, ControllerBase, route
from django.shortcuts import get_object_or_404 from django.db import transaction
# 导入文档处理模块 from django.shortcuts import get_object_or_404
from docxtpl import DocxTemplate, InlineImage # 导入文档处理模块
# 导入ORM模型 from docxtpl import DocxTemplate, InlineImage
from apps.project.models import Project # 导入ORM模型
# 导入工具 from apps.project.models import Project, Case
from utils.util import get_str_abbr, get_str_dict # 导入工具
from utils.chen_response import ChenResponse from utils.util import get_str_abbr, get_str_dict
from utils.path_utils import project_path from utils.chen_response import ChenResponse
from apps.createDocument.extensions.parse_rich_text import RichParser from utils.path_utils import project_path
# 导入生成日志记录模块 from apps.createDocument.extensions.parse_rich_text import RichParser
from apps.createSeiTaiDocument.extensions.logger import GenerateLogger # 导入生成日志记录模块
from apps.createSeiTaiDocument.extensions.logger import GenerateLogger
gloger = GenerateLogger("问题单二段文档")
gloger = GenerateLogger("问题单二段文档")
# @api_controller("/generateWtd", tags=['生成问题单文档系列'], auth=JWTAuth(), permissions=[IsAuthenticated])
@api_controller('/generateWtd', tags=['生成问题单文档系列']) # @api_controller("/generateWtd", tags=['生成问题单文档系列'], auth=JWTAuth(), permissions=[IsAuthenticated])
class GenerateControllerWtd(ControllerBase): @api_controller('/generateWtd', tags=['生成问题单文档系列'])
@route.get("/create/problem", url_name="create-problem") class GenerateControllerWtd(ControllerBase):
@transaction.atomic @route.get("/create/problem", url_name="create-problem")
def create_problem(self, id: int): @transaction.atomic
"""生成问题单""" def create_problem(self, id: int):
project_path_str = project_path(id) """生成问题单"""
tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/wtd' / '问题详情表.docx' project_path_str = project_path(id)
doc = DocxTemplate(tpl_path) tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/wtd' / '问题详情表.docx'
project_obj = get_object_or_404(Project, id=id) doc = DocxTemplate(tpl_path)
problem_list = list(project_obj.projField.distinct()) # 去掉重复因为和case是多对多 project_obj = get_object_or_404(Project, id=id)
problem_list.sort(key=lambda x: int(x.ident)) problem_list = list(project_obj.projField.distinct()) # 去掉重复因为和case是多对多
data_list = [] problem_list.sort(key=lambda x: int(x.ident))
for problem in problem_list: data_list = []
problem_dict = {'ident': problem.ident, 'name': problem.name} for problem in problem_list:
# 1.生成被测对象名称、被测对象标识、被测对象版本 problem_dict = {'ident': problem.ident, 'name': problem.name}
cases = problem.case.all() # 1.生成被测对象名称、被测对象标识、被测对象版本
# generate_log:无关联问题单进入生成日志 cases: QuerySet[Case] = problem.case.all()
if cases.count() < 1: # generate_log:无关联问题单进入生成日志
gloger.write_warning_log('单个问题单表格', f'问题单{problem.ident}未关联用例,请检查') if cases.count() < 1:
str_dut_name_list = [] gloger.write_warning_log('单个问题单表格', f'问题单{problem.ident}未关联用例,请检查')
str_dut_ident_list = [] str_dut_name_list = []
str_dut_version_list = [] str_dut_ident_list = []
# 2.所属用例标识 str_dut_version_list = []
case_ident_list = [] # 2.所属用例标识
# 3.获取依据要求 case_ident_list = []
case_design_list = [] # 3.获取依据要求
for case in cases: case_design_list = []
if case.test.testType == '8': for case in cases:
# 1.1.如果为文档审查,提取所属文档名称、文档被测件标识、文档被测件版本 if case.test.testType == '8':
str_dut_name_list.append(case.dut.name) # 1.1.如果为文档审查,提取所属文档名称、文档被测件标识、文档被测件版本
str_dut_ident_list.append(case.dut.ref) str_dut_name_list.append(case.dut.name)
str_dut_version_list.append(case.dut.version) str_dut_ident_list.append(case.dut.ref)
# 对应dut名称design章节号design描述 str_dut_version_list.append(case.dut.version)
case_design_list.append("".join([case.dut.name, case.design.chapter])) # 对应dut名称design章节号design描述
else: case_design_list.append("".join([case.dut.name, case.design.chapter]))
# 1.2.如果不为文档审查则提取该轮次源代码dut的信息 else:
so_dut = case.round.rdField.filter(type='SO').first() # 1.2.如果不为文档审查则提取该轮次源代码dut的信息
if so_dut: so_dut = case.round.rdField.filter(type='SO').first()
str_dut_name_list.append(project_obj.name + '软件') if so_dut:
str_dut_ident_list.append(so_dut.ref) str_dut_name_list.append(project_obj.name + '软件')
str_dut_version_list.append(so_dut.version) str_dut_ident_list.append(so_dut.ref)
# TODO:如何处理设计需求的内容,暂时设置为取出图片,只保留文字 str_dut_version_list.append(so_dut.version)
p_list = [] # TODO:如何处理设计需求的内容,暂时设置为取出图片,只保留文字
rich_parse_remove_img = RichParser(case.design.description) p_list = []
rich_list = rich_parse_remove_img.get_final_list(doc) rich_parse_remove_img = RichParser(case.design.description)
for rich in rich_list: rich_list = rich_parse_remove_img.get_final_list(doc)
if isinstance(rich, dict) or isinstance(rich, InlineImage): for rich in rich_list:
continue if isinstance(rich, dict) or isinstance(rich, InlineImage):
else: continue
p_list.append(rich) else:
p_list.append(rich)
case_design_list.append( case_design_list.append("-".join([case.dut.name, case.design.chapter + '章节' + ":" + ''.join(p_list)]))
"-".join([case.dut.name, case.design.chapter + '章节' + ":" + ''.join(p_list)])) # 2.用例标识修改-YL_测试项类型_测试项标识_用例key+1
# 2.用例标识修改-YL_测试项类型_测试项标识_用例key+1 demand = case.test # 中间变量
demand = case.test # 中间变量 demand_testType = demand.testType # 中间变量
demand_testType = demand.testType # 中间变量 testType_abbr = get_str_abbr(demand_testType, 'testType') # 输出FT
testType_abbr = get_str_abbr(demand_testType, 'testType') # 输出FT case_ident_list.append("_".join(
case_ident_list.append("_".join( ['YL', testType_abbr, demand.ident, str(int(case.key[-1]) + 1).rjust(3, '0')]))
['YL', testType_abbr, demand.ident, str(int(case.key[-1]) + 1).rjust(3, '0')])) problem_dict['duts_name'] = "/".join(set(str_dut_name_list))
problem_dict['duts_name'] = "/".join(set(str_dut_name_list)) problem_dict['duts_ref'] = "/".join(set(str_dut_ident_list))
problem_dict['duts_ref'] = "/".join(set(str_dut_ident_list)) problem_dict['duts_version'] = "/".join(set(str_dut_version_list))
problem_dict['duts_version'] = "/".join(set(str_dut_version_list)) temp_name_version = []
temp_name_version = [] for i in range(len(str_dut_name_list)):
for i in range(len(str_dut_name_list)): temp_name_version.append(
temp_name_version.append( "".join([str_dut_name_list[i] + str_dut_ident_list[i], '/V', str_dut_version_list[i]]))
"".join([str_dut_name_list[i] + str_dut_ident_list[i], '/V', str_dut_version_list[i]])) problem_dict['dut_name_version'] = "\a".join(set(temp_name_version))
problem_dict['dut_name_version'] = "\a".join(temp_name_version) problem_dict['case_ident'] = "".join(set(case_ident_list))
problem_dict['case_ident'] = "".join(set(case_ident_list)) problem_dict['type'] = get_str_dict(problem.type, 'problemType')
problem_dict['type'] = get_str_dict(problem.type, 'problemType') problem_dict['grade'] = get_str_dict(problem.grade, 'problemGrade')
problem_dict['grade'] = get_str_dict(problem.grade, 'problemGrade')
# 依据要求-获取其设计需求
# 依据要求-获取其设计需求 print(case_design_list)
problem_dict['yaoqiu'] = "\a".join(case_design_list) problem_dict['yaoqiu'] = "\a".join(case_design_list)
# 问题操作 - HTML解析 # 问题操作 - HTML解析
desc_list = ['【问题操作】'] desc_list = ['【问题操作】']
rich_parser = RichParser(problem.operation) rich_parser = RichParser(problem.operation)
desc_list.extend(rich_parser.get_final_list(doc)) desc_list.extend(rich_parser.get_final_list(doc))
# 问题影响 # 问题影响
desc_list_result = [f'\a【问题影响】\a{problem.result}'] desc_list_result = [f'\a【问题影响】\a{problem.result}']
desc_list.extend(desc_list_result) desc_list.extend(desc_list_result)
# 问题描述赋值 # 问题描述赋值
problem_dict['desc'] = desc_list problem_dict['desc'] = desc_list
# 4.原因分析 # 4.原因分析
desc_list_3 = [f'【原因分析】\a{problem.analysis}'] desc_list_3 = [f'【原因分析】\a{problem.analysis}']
problem_dict['cause'] = desc_list_3 problem_dict['cause'] = desc_list_3
# 5.影响域分析~~~~ # 5.影响域分析~~~~
desc_list_4 = [f'【影响域分析】\a{problem.effect_scope}'] desc_list_4 = [f'【影响域分析】\a{problem.effect_scope}']
problem_dict['effect_scope'] = desc_list_4 problem_dict['effect_scope'] = desc_list_4
# 6.改正措施 # 6.改正措施
problem_dict['solve'] = problem.solve problem_dict['solve'] = problem.solve
# 7.回归验证结果 # 7.回归验证结果
desc_list_5 = [] desc_list_5 = []
rich_parser5 = RichParser(problem.verify_result) rich_parser5 = RichParser(problem.verify_result)
desc_list_5.extend(rich_parser5.get_final_list(doc)) desc_list_5.extend(rich_parser5.get_final_list(doc))
problem_dict['verify_result'] = desc_list_5 problem_dict['verify_result'] = desc_list_5
# 8.其他日期和人员 # 8.其他日期和人员
problem_dict['postPerson'] = problem.postPerson problem_dict['postPerson'] = problem.postPerson
problem_dict['postDate'] = problem.postDate problem_dict['postDate'] = problem.postDate
close_str = '□修改文档 □修改程序 □不修改' close_str = '□修改文档 □修改程序 □不修改'
if len(problem.closeMethod) < 1: if len(problem.closeMethod) < 1:
close_str = '□修改文档 □修改程序 ■不修改' close_str = '□修改文档 □修改程序 ■不修改'
elif len(problem.closeMethod) == 2: elif len(problem.closeMethod) == 2:
close_str = '■修改文档 ■修改程序 □不修改' close_str = '■修改文档 ■修改程序 □不修改'
else: else:
if problem.closeMethod[0] == '1': if problem.closeMethod[0] == '1':
close_str = '■修改文档 □修改程序 □不修改' close_str = '■修改文档 □修改程序 □不修改'
elif problem.closeMethod[0] == '2': elif problem.closeMethod[0] == '2':
close_str = '□修改文档 ■修改程序 □不修改' close_str = '□修改文档 ■修改程序 □不修改'
else: else:
close_str = '□修改文档 □修改程序 □不修改' close_str = '□修改文档 □修改程序 □不修改'
problem_dict['closeMethod'] = close_str problem_dict['closeMethod'] = close_str
problem_dict['designer'] = problem.designerPerson problem_dict['designer'] = problem.designerPerson
problem_dict['designDate'] = problem.designDate problem_dict['designDate'] = problem.designDate
problem_dict['verifyPerson'] = problem.verifyPerson problem_dict['verifyPerson'] = problem.verifyPerson
problem_dict['verifyDate'] = problem.verifyDate problem_dict['verifyDate'] = problem.verifyDate
data_list.append(problem_dict) data_list.append(problem_dict)
context = { context = {
'project_name': project_obj.name, 'project_name': project_obj.name,
'project_ident': project_obj.ident, 'project_ident': project_obj.ident,
'problem_list': data_list, 'problem_list': data_list,
} }
doc.render(context, autoescape=True) doc.render(context, autoescape=True)
try: try:
doc.save(Path.cwd() / "media" / project_path_str / "output_dir/wtd" / '问题详情表.docx') doc.save(Path.cwd() / "media" / project_path_str / "output_dir/wtd" / '问题详情表.docx')
return ChenResponse(status=200, code=200, message="文档生成成功!") return ChenResponse(status=200, code=200, message="文档生成成功!")
except PermissionError as e: except PermissionError as e:
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e)) return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))

View File

@@ -1,141 +1,143 @@
""" """
专门解析富文本插件tinymce的html内容 专门解析富文本插件tinymce的html内容
""" """
import pandas as pd import pandas as pd
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from bs4.element import Tag, NavigableString from bs4.element import Tag, NavigableString
import base64 import base64
import io import io
from docxtpl import InlineImage from docxtpl import InlineImage
from docx.shared import Mm from docx.shared import Mm
import re import re
# text.replace('\xa0', ' ')) # text.replace('\xa0', ' '))
class RichParser: class RichParser:
def __init__(self, rich_text): def __init__(self, rich_text):
# 将rich_text的None变为空字符串鲁棒 # 将rich_text的None变为空字符串鲁棒
if rich_text is None: if rich_text is None:
rich_text = "" rich_text = ""
# 对原始html解析后的bs对象 # 对原始html解析后的bs对象
self.bs = BeautifulSoup(rich_text, 'html.parser') self.bs = BeautifulSoup(rich_text, 'html.parser')
self.content = self.remove_n_in_contents() self.content = self.remove_n_in_contents()
# 最终的解析后的列表 # 最终的解析后的列表
self.data_list = [] self.data_list = []
self.line_parse() self.line_parse()
# 匹配“表1-3”或“表1”等字符的正则 # 匹配“表1-3”或“表1”等字符的正则
self.biao_pattern = re.compile(r"\d+(?:-\d+)?") self.biao_pattern = re.compile(r"\d+(?:-\d+)?")
# 1.函数将self.bs.contents去掉\n获取每行数据 # 1.函数将self.bs.contents去掉\n获取每行数据
def remove_n_in_contents(self): def remove_n_in_contents(self):
content_list = [] content_list = []
for line in self.bs.contents: for line in self.bs.contents:
if line != '\n': if line != '\n':
content_list.append(line) content_list.append(line)
return content_list return content_list
# 2.逐个遍历self.content去掉table元素Tag对象单独解析 # 2.逐个遍历self.content去掉table元素Tag对象单独解析
def line_parse(self): def line_parse(self):
for tag in self.content: for tag in self.content:
if isinstance(tag, NavigableString): if isinstance(tag, NavigableString):
self.data_list.append(tag.text) self.data_list.append(tag.text)
elif isinstance(tag, Tag): elif isinstance(tag, Tag):
if tag.name == 'p': if tag.name == 'p':
img_list = tag.find_all('img') img_list = tag.find_all('img')
if len(img_list) > 0: if len(img_list) > 0:
for img_item in img_list: for img_item in img_list:
self.data_list.append(img_item.get('src')) self.data_list.append(img_item.get('src'))
else: else:
self.data_list.append(tag.text) self.data_list.append(tag.text)
elif tag.name == 'table': elif tag.name == 'table':
df_dict_list = self.parse_tag2list(tag) df_dict_list = self.parse_tag2list(tag)
self.data_list.append(df_dict_list) self.data_list.append(df_dict_list)
elif tag.name == 'div': elif tag.name == 'div':
table_list = tag.find_all('table') table_list = tag.find_all('table')
if len(table_list) > 0: if len(table_list) > 0:
for table in table_list: for table in table_list:
df_dict_list = self.parse_tag2list(table) df_dict_list = self.parse_tag2list(table)
self.data_list.append(df_dict_list) self.data_list.append(df_dict_list)
# 3.1.辅助方法,将<table>的Tag对象转为[[]]二维列表格式 # 3.1.辅助方法,将<table>的Tag对象转为[[]]二维列表格式
def parse_tag2list(self, table_tag): def parse_tag2list(self, table_tag):
# str(tag)可直接变成<table>xxx</table> # str(tag)可直接变成<table>xxx</table>
pd_list = pd.read_html(io.StringIO(str(table_tag))) pd_list = pd.read_html(io.StringIO(str(table_tag)))
# 将dataframe变为数组 # 将dataframe变为数组
df = pd_list[0] df = pd_list[0]
# 处理第一行为数字的情况,如果为数字则删除第一行,让第二行为列名 # 处理第一行为数字的情况,如果为数字则删除第一行,让第二行为列名
if all(isinstance(col, int) for col in df.columns): if all(isinstance(col, int) for col in df.columns):
df.columns = df.iloc[0] df.columns = df.iloc[0]
df = df.drop(0) # 删除原来的第一行 df = df.drop(0) # 删除原来的第一行
# 转为列表的列表(二维列表) # 转为列表的列表(二维列表)
# return df.values.tolist() # return df.values.tolist()
return df.fillna('').T.reset_index().T.values.tolist() return df.fillna('').T.reset_index().T.values.tolist()
# 3.2.辅助方法,打印解析后列表 # 3.2.辅助方法,打印解析后列表
def print_content(self): def print_content(self):
for line in self.data_list: for line in self.data_list:
print(line) print(line)
# 4.1.最终方法生成给docxtpl可用的列表 -> 注意需要传递DocxTemplate对象在接口函数里面初始化的 # 4.1.最终方法生成给docxtpl可用的列表 -> 注意需要传递DocxTemplate对象在接口函数里面初始化的
def get_final_list(self, doc, /, *, img_size=100, height=80): def get_final_list(self, doc, /, *, img_size=100, height=80):
"""注意关键字传参可修改图片大小img_size:int=100""" """注意关键字传参可修改图片大小img_size:int=100"""
final_list = [] final_list = []
for oneline in self.data_list: for oneline in self.data_list:
# 这里要单独处理下二维列表 # 这里要单独处理下二维列表
if isinstance(oneline, list): if isinstance(oneline, list):
final_list.append({'isTable': True, 'data': oneline}) final_list.append({'isTable': True, 'data': oneline})
continue continue
if oneline.startswith("data:image/png;base64") or oneline.startswith("data:image/jpeg;base64,") or oneline.startswith( if oneline.startswith("data:image/png;base64") or oneline.startswith("data:image/jpeg;base64,") or oneline.startswith(
"data:image/jpg;base64,"): "data:image/jpg;base64,"):
base64_bytes = base64.b64decode(oneline.replace("data:image/png;base64,", "")) base64_bytes = base64.b64decode(oneline.replace("data:image/png;base64,", ""))
# ~~~设置了固定宽度、高度~~~ # ~~~设置了固定宽度、高度~~~
inline_image = InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(img_size), height=Mm(height)) inline_image = InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(img_size), height=Mm(height))
final_list.append(inline_image) final_list.append(inline_image)
else: else:
final_list.append(oneline) # ~~~新增:将\xa0修改为普通空格~~~
if len(final_list) <= 0: oneline = oneline.replace('\xa0', ' ')
final_list.append("") final_list.append(oneline)
# 针对tinymce中粘贴表格最后一行显示句号问题这里统一删除 if len(final_list) <= 0:
if final_list[-1] == '\xa0': final_list.append("")
final_list.pop() # 针对tinymce中粘贴表格最后一行显示句号问题这里统一删除
return final_list if final_list[-1] == '\xa0':
final_list.pop()
# 4.2.最终方法,在上面方法基础上,增加格式,例如<p>增加缩进,图片居中,<p>包含“图x”则居中 return final_list
def get_final_format_list(self, doc, /, *, img_size=115, height=80):
final_list = [] # 4.2.最终方法,在上面方法基础上,增加格式,例如<p>增加缩进,图片居中,<p>包含“图x”则居中
for oneline in self.data_list: def get_final_format_list(self, doc, /, *, img_size=115, height=80):
# 这里要单独处理下二维列表 final_list = []
if isinstance(oneline, list): for oneline in self.data_list:
final_list.append({'isTable': True, 'data': oneline}) # 这里要单独处理下二维列表
continue if isinstance(oneline, list):
if oneline.startswith("data:image/png;base64"): final_list.append({'isTable': True, 'data': oneline})
base64_bytes = base64.b64decode(oneline.replace("data:image/png;base64,", "")) continue
# 1.和上面函数变化图片更改为dict然后isCenter属性居中 if oneline.startswith("data:image/png;base64"):
final_list.append( base64_bytes = base64.b64decode(oneline.replace("data:image/png;base64,", ""))
{'isCenter': True, # 1.和上面函数变化图片更改为dict然后isCenter属性居中
'data': InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(img_size), height=height)}) final_list.append(
else: {'isCenter': True,
# 2.和上面区别:如果<p>带有“图”则居中 'data': InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(img_size), height=height)})
if re.match(r"[表图]\d.*", oneline): else:
final_list.append({"isCenter": True, "data": oneline}) # 2.和上面区别:如果<p>带有“图”则居中
else: if re.match(r"[表图]\d.*", oneline):
final_list.append({"isCenter": False, "data": oneline}) final_list.append({"isCenter": True, "data": oneline.replace('\xa0', ' ')})
if len(final_list) <= 0: else:
final_list.append("") final_list.append({"isCenter": False, "data": oneline.replace('\xa0', ' ')})
return final_list if len(final_list) <= 0:
final_list.append("")
# 5.最终方法去掉图片和table元素 -> 纯文本列表 return final_list
def get_final_p_list(self):
final_list = [] # 5.最终方法去掉图片和table元素 -> 纯文本列表
for oneline in self.data_list: def get_final_p_list(self):
if isinstance(oneline, list) or oneline.startswith("data:image/png;base64"): final_list = []
continue for oneline in self.data_list:
cleaned_line = oneline if isinstance(oneline, list) or oneline.startswith("data:image/png;base64"):
cleaned_line = re.sub(r'\s+', '', cleaned_line) continue
cleaned_line = cleaned_line.replace(')', '') cleaned_line = oneline
cleaned_line = cleaned_line.strip() cleaned_line = re.sub(r'\s+', '', cleaned_line)
# 去掉以“表3”的行 cleaned_line = cleaned_line.replace(')', '')
if self.biao_pattern.search(cleaned_line): cleaned_line = cleaned_line.strip()
continue # 去掉以“表3”的行
if cleaned_line: if self.biao_pattern.search(cleaned_line):
final_list.append(cleaned_line) continue
return final_list if cleaned_line:
final_list.append(cleaned_line)
return final_list

View File

@@ -257,7 +257,7 @@ class CaseController(ControllerBase):
single_qs.key = case_key single_qs.key = case_key
index = index + 1 index = index + 1
single_qs.save() single_qs.save()
return ChenResponse(message="测试用例删除成功!") return ChenResponse(message="测试用例删除成功!影响域分析中如果有该关联用例则被删除。")
# 右键测试项,根据测试子项生成用例 # 右键测试项,根据测试子项生成用例
@route.post("/case/create_by_demand", url_name='case-create-by-demand') @route.post("/case/create_by_demand", url_name='case-create-by-demand')

View File

@@ -0,0 +1,24 @@
# Generated by Django 6.0.4 on 2026-04-17 13:57
import apps.project.models
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0029_influenceitem_change_influ'),
]
operations = [
migrations.AlterField(
model_name='project',
name='devplant',
field=models.JSONField(blank=True, default=apps.project.models.create_list, help_text='开发环境', null=True, verbose_name='开发环境'),
),
migrations.AlterField(
model_name='project',
name='runtime',
field=models.JSONField(blank=True, default=apps.project.models.create_list, help_text='运行环境', null=True, verbose_name='运行环境'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 6.0.4 on 2026-04-17 16:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0030_alter_project_devplant_alter_project_runtime'),
]
operations = [
migrations.AlterField(
model_name='testdemand',
name='adequacy',
field=models.CharField(blank=True, help_text='充分条件', max_length=2048, null=True, verbose_name='充分条件'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 6.0.4 on 2026-04-20 10:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0031_alter_testdemand_adequacy'),
]
operations = [
migrations.AlterField(
model_name='design',
name='protocal',
field=models.CharField(blank=True, default='', help_text='接口数据', max_length=1024, null=True, verbose_name='接口数据'),
),
]

View File

@@ -27,50 +27,29 @@ class Project(CoreModel):
vise_person = models.CharField(max_length=64, verbose_name="质量监督员", help_text="质量监督员") vise_person = models.CharField(max_length=64, verbose_name="质量监督员", help_text="质量监督员")
config_person = models.CharField(max_length=64, verbose_name="配置管理员", help_text="配置管理员") config_person = models.CharField(max_length=64, verbose_name="配置管理员", help_text="配置管理员")
# ~~~~~~~~~~~ # ~~~~~~~~~~~
security_level = models.CharField(max_length=8, blank=True, null=True, verbose_name="安全等级", security_level = models.CharField(max_length=8, blank=True, null=True, verbose_name="安全等级", help_text="安全等级")
help_text="安全等级") test_level = models.JSONField(null=True, blank=True, help_text="测试级别", verbose_name="测试级别", default=create_list)
test_level = models.JSONField(null=True, blank=True, help_text="测试级别", verbose_name="测试级别", plant_type = models.JSONField(null=True, blank=True, help_text="平台类型", verbose_name="平台类型", default=create_list)
default=create_list) report_type = models.CharField(max_length=64, blank=True, null=True, verbose_name="报告类型", help_text="报告类型")
plant_type = models.JSONField(null=True, blank=True, help_text="平台类型", verbose_name="平台类型", language = models.JSONField(null=True, blank=True, help_text="被测语言", verbose_name="被测语言", default=create_list)
default=create_list) standard = models.JSONField(null=True, blank=True, help_text="依据标准", verbose_name="依据标准", default=create_list)
report_type = models.CharField(max_length=64, blank=True, null=True, verbose_name="报告类型",
help_text="报告类型")
language = models.JSONField(null=True, blank=True, help_text="被测语言", verbose_name="被测语言",
default=create_list)
standard = models.JSONField(null=True, blank=True, help_text="依据标准", verbose_name="依据标准",
default=create_list)
entrust_unit = models.CharField(max_length=64, verbose_name="委托方单位", help_text="委托方单位") entrust_unit = models.CharField(max_length=64, verbose_name="委托方单位", help_text="委托方单位")
entrust_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方联系人", entrust_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方联系人", help_text="委托方联系人")
help_text="委托方联系人") entrust_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方电话", help_text="委托方电话")
entrust_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方电话", entrust_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方邮箱", help_text="委托方邮箱")
help_text="委托方电话")
entrust_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="委托方邮箱",
help_text="委托方邮箱")
dev_unit = models.CharField(max_length=64, verbose_name="开发方单位", help_text="开发方单位") dev_unit = models.CharField(max_length=64, verbose_name="开发方单位", help_text="开发方单位")
dev_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方联系人", dev_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方联系人", help_text="研制方联系人")
help_text="研制方联系人") dev_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方电话", help_text="研制方电话")
dev_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方电话", dev_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方邮箱", help_text="研制方邮箱")
help_text="研制方电话")
dev_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="研制方邮箱",
help_text="研制方邮箱")
test_unit = models.CharField(max_length=64, verbose_name="测试方单位", help_text="测试方单位") test_unit = models.CharField(max_length=64, verbose_name="测试方单位", help_text="测试方单位")
test_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心联系人", test_contact = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心联系人", help_text="测评中心联系人")
help_text="测评中心联系人") test_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心电话", help_text="测评中心电话")
test_contact_phone = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心电话", test_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心邮箱", help_text="测评中心邮箱")
help_text="测评中心电话") step = models.CharField(max_length=8, blank=True, null=True, verbose_name="项目阶段", help_text="项目阶段")
test_email = models.CharField(max_length=64, blank=True, null=True, verbose_name="测评中心邮箱", abbreviation = models.JSONField(null=True, blank=True, help_text="缩略语", verbose_name="缩略语", default=create_list)
help_text="测评中心邮箱") soft_type = models.SmallIntegerField(verbose_name='软件类型', choices=((1, '新研'), (2, '改造'), (3, '沿用')), default=1)
step = models.CharField(max_length=8, blank=True, null=True, verbose_name="项目阶段", runtime = models.JSONField(null=True, blank=True, help_text="运行环境", verbose_name="运行环境", default=create_list)
help_text="项目阶段") devplant = models.JSONField(null=True, blank=True, help_text="开发环境", verbose_name="开发环境", default=create_list)
abbreviation = models.JSONField(null=True, blank=True, help_text="缩略语", verbose_name="缩略语",
default=create_list)
soft_type = models.SmallIntegerField(verbose_name='软件类型',
choices=((1, '新研'), (2, '改造'), (3, '沿用')),
default=1)
runtime = models.CharField(max_length=8, blank=True, null=True, verbose_name="运行环境",
help_text="运行环境")
devplant = models.CharField(max_length=8, blank=True, null=True, verbose_name="开发环境",
help_text="开发环境")
# 9月2日新增字段密级 # 9月2日新增字段密级
secret = models.CharField(max_length=30, default='1', verbose_name='密级', help_text='密级') secret = models.CharField(max_length=30, default='1', verbose_name='密级', help_text='密级')
@@ -226,7 +205,7 @@ class Design(CoreModel):
type = models.CharField(max_length=64, blank=True, null=True, default='', verbose_name='接口类型', type = models.CharField(max_length=64, blank=True, null=True, default='', verbose_name='接口类型',
help_text='接口类型') help_text='接口类型')
# 注意:该字段改为接口数据 # 注意:该字段改为接口数据
protocal = models.CharField(max_length=64, blank=True, null=True, default='', verbose_name='接口数据', protocal = models.CharField(max_length=1024, blank=True, null=True, default='', verbose_name='接口数据',
help_text='接口数据') help_text='接口数据')
def __str__(self): def __str__(self):
@@ -239,23 +218,15 @@ class Design(CoreModel):
ordering = ('key',) ordering = ('key',)
class TestDemand(CoreModel): class TestDemand(CoreModel):
objects = models.Manager()
"""测试项""" """测试项"""
ident = models.CharField(max_length=64, blank=True, null=True, verbose_name="测试需求标识", objects = models.Manager()
help_text="测试需求标识") ident = models.CharField(max_length=64, blank=True, null=True, verbose_name="测试需求标识", help_text="测试需求标识")
name = models.CharField(max_length=64, blank=True, null=True, verbose_name="测试需求名称", name = models.CharField(max_length=64, blank=True, null=True, verbose_name="测试需求名称", help_text="测试需求名称")
help_text="测试需求名称") adequacy = models.CharField(max_length=2048, blank=True, null=True, verbose_name="充分条件", help_text="充分条件")
adequacy = models.CharField(max_length=256, blank=True, null=True, verbose_name="充分条件", priority = models.CharField(max_length=8, blank=True, null=True, verbose_name="优先级", help_text="优先级")
help_text="充分条件") testType = models.CharField(max_length=8, null=True, blank=True, help_text="测试类型", verbose_name="测试类型", default="1")
priority = models.CharField(max_length=8, blank=True, null=True, verbose_name="优先级", testMethod = models.JSONField(blank=True, help_text="测试方法", verbose_name="测试方法", default=create_list)
help_text="优先级") title = models.CharField(max_length=64, blank=True, null=True, verbose_name="树-名称", help_text="树-名称")
testType = models.CharField(max_length=8, null=True, blank=True, help_text="测试类型",
verbose_name="测试类型",
default="1")
testMethod = models.JSONField(blank=True, help_text="测试方法", verbose_name="测试方法",
default=create_list)
title = models.CharField(max_length=64, blank=True, null=True, verbose_name="树-名称",
help_text="树-名称")
key = models.CharField(max_length=64, blank=True, null=True, key = models.CharField(max_length=64, blank=True, null=True,
verbose_name="round-dut-designkey-testdemand", verbose_name="round-dut-designkey-testdemand",
help_text="round-dut-designkey-testdemand") help_text="round-dut-designkey-testdemand")

View File

@@ -1,91 +1,132 @@
import jwt import jwt
from django.conf import settings from django.conf import settings
from threading import local from threading import local
from django.db.models.signals import post_save, post_delete from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.functional import SimpleLazyObject from django.utils.functional import SimpleLazyObject
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
# 导入日志的模型 # 导入用例和影响域分析Model-设计信号当删除用例对应影响域分析删除关联用例
from apps.user.models import TableOperationLog, Users from apps.project.models import Case, InfluenceItem
# 导入其他模型用于排除 # 导入日志的模型
from apps.project.models import CaseStep, TestDemandContent from apps.user.models import TableOperationLog, Users
# 导入异常处理 # 导入其他模型用于排除
from jwt.exceptions import ExpiredSignatureError from apps.project.models import CaseStep, TestDemandContent
from utils.chen_response import ChenResponse # 导入异常处理
# 导入中间件记录日志模型 from jwt.exceptions import ExpiredSignatureError
from apps.system.models import LoginLog from utils.chen_response import ChenResponse
from apps.system.models import OperationLog # 导入中间件记录日志模型
from apps.system.models import LoginLog
log_manager = TableOperationLog.objects from apps.system.models import OperationLog
_thread_local = local() log_manager = TableOperationLog.objects
def get_current_user(): _thread_local = local()
"""
获取当前用户对象调用则从local对象里面获取user def get_current_user():
:return: Users实例 """
""" 获取当前用户对象调用则从local对象里面获取user
return getattr(_thread_local, 'user', None) :return: Users实例
"""
def clear_request_locals(sender, **kwargs): return getattr(_thread_local, 'user', None)
"""
被request_finished连接的信号处理函数请求结束后清除local里面的user信息 def clear_request_locals(sender, **kwargs):
""" """
_thread_local.user = None 被request_finished连接的信号处理函数请求结束后清除local里面的user信息
"""
def set_request_locals(sender, **kwargs): _thread_local.user = None
"""
被request_started连接的信号处理函数_thread_local.user属性设置为当前登录用户 def set_request_locals(sender, **kwargs):
""" """
bearer_token = kwargs['environ'].get('HTTP_AUTHORIZATION', None) 被request_started连接的信号处理函数_thread_local.user属性设置为当前登录用户
if not bearer_token or bearer_token == 'Bearer null': """
return bearer_token = kwargs['environ'].get('HTTP_AUTHORIZATION', None)
bearer_token = bearer_token.replace('Bearer ', '') if not bearer_token or bearer_token == 'Bearer null':
# 逻辑先获取NINJA_JWT配置中秘钥、和加密算法信息 return
jwt_settings = settings.NINJA_JWT bearer_token = bearer_token.replace('Bearer ', '')
jwt_secret = jwt_settings.get('SIGNING_KEY', None) # 逻辑先获取NINJA_JWT配置中秘钥、和加密算法信息
jwt_algo = jwt_settings.get('ALGORITHM', None) jwt_settings = settings.NINJA_JWT
# 如果为None则使用settings中的秘钥和['HS256']算法 jwt_secret = jwt_settings.get('SIGNING_KEY', None)
secret_key = jwt_secret or settings.SECRET_KEY jwt_algo = jwt_settings.get('ALGORITHM', None)
algorithms_str = jwt_algo or 'HS256' # 如果为None则使用settings中的秘钥和['HS256']算法
# 解决bug:因为过期前面不跳转首页处理方式 secret_key = jwt_secret or settings.SECRET_KEY
try: algorithms_str = jwt_algo or 'HS256'
jwt_dict = jwt.decode(bearer_token, secret_key, algorithms=[algorithms_str]) # 解决bug:因为过期前面不跳转首页处理方式
except ExpiredSignatureError as exc: try:
return ChenResponse(status=403, code=500, message='您的token已过期请重新登录') jwt_dict = jwt.decode(bearer_token, secret_key, algorithms=[algorithms_str])
user_id = jwt_dict.get('user_id', None) except ExpiredSignatureError as exc:
if user_id: return ChenResponse(status=403, code=500, message='您的token已过期请重新登录')
_thread_local.user = SimpleLazyObject(lambda: get_user_model().objects.get(id=user_id)) user_id = jwt_dict.get('user_id', None)
if user_id:
# 1.注意可以不传sender为监听所有模型这里来记录日志 _thread_local.user = SimpleLazyObject(lambda: get_user_model().objects.get(id=user_id))
# 2.使用get_current_user()获取当前请求用户
@receiver(post_save) # 1.注意可以不传sender为监听所有模型这里来记录日志
def post_save_handler(sender, instance, created, **kwargs): # 2.使用get_current_user()获取当前请求用户
"""模型新增-操作日志填写""" @receiver(post_save)
# 注意排除日志模块、用例步骤表、测试项步骤表 def post_save_handler(sender, instance, created, **kwargs):
if (sender == TableOperationLog or sender == CaseStep or sender == TestDemandContent or sender == LoginLog or sender == OperationLog or sender """模型新增-操作日志填写"""
== Users): # 注意排除日志模块、用例步骤表、测试项步骤表
return if (sender == TableOperationLog or sender == CaseStep or sender == TestDemandContent or sender == LoginLog or sender == OperationLog or sender
user = get_current_user() == Users):
ope_dict = { return
'operate_obj': str(instance), user = get_current_user()
} ope_dict = {
if created: 'operate_obj': str(instance),
ope_dict['operate_des'] = '新增' }
else: if created:
ope_dict['operate_des'] = '修改' ope_dict['operate_des'] = '新增'
log_manager.create(user=user, **ope_dict) else:
ope_dict['operate_des'] = '修改'
@receiver(post_delete) log_manager.create(user=user, **ope_dict)
def post_delete_handler(sender, instance, **kwargs):
"""模型删除-操作日志填写""" @receiver(post_delete)
# 注意排除日志模块、用例步骤表、测试项步骤表 def post_delete_handler(sender, instance, **kwargs):
if (sender == TableOperationLog or sender == CaseStep or sender == TestDemandContent or sender == LoginLog or sender == OperationLog or sender """模型删除-操作日志填写"""
== Users): # 注意排除日志模块、用例步骤表、测试项步骤表
return if (sender == TableOperationLog or sender == CaseStep or sender == TestDemandContent or sender == LoginLog or sender == OperationLog or sender
user = get_current_user() == Users):
ope_dict = { return
'operate_obj': str(instance), user = get_current_user()
'operate_des': '删除' ope_dict = {
} 'operate_obj': str(instance),
log_manager.create(user=user, **ope_dict) 'operate_des': '删除'
}
log_manager.create(user=user, **ope_dict)
# 信号:删除影响域分析关联的用例,将影响域分析管理用例删除
@receiver(post_delete, sender=Case)
def clean_up_deleted_case_reference_from_influence(sender, instance, **kwargs):
"""
监听 Case 的删除信号。
仅在同一个 Project 范围内,从 InfluenceItem 的 effect_cases 中移除被删用例的 key。
"""
deleted_key = instance.key
project_id = instance.project_id
if not deleted_key or not project_id:
return
# 查询当前项目的影响域分析并且包含该用例
items = InfluenceItem.objects.filter(
influence__round__project_id=project_id, # 外键链锁定项目
effect_cases__contains=[deleted_key] # JSON 字段包含该 key
)
# 未发现有关联的影响域分析则不处理
if not items.exists():
return
# 更新影响域分析的关联用例
updated_items = []
for item in items:
original_keys = item.effect_cases
# 过滤掉被删除的 key保留其他
new_keys = [k for k in original_keys if k != deleted_key]
if len(new_keys) != len(original_keys):
item.effect_cases = new_keys
updated_items.append(item)
if updated_items:
InfluenceItem.objects.bulk_update(updated_items, ['effect_cases'])
else:
print("⚠️ 查询到记录但未发生变更,可能数据有误")

Binary file not shown.

View File

@@ -1,83 +1,83 @@
"""全部是生产环境配置""" """全部是生产环境配置"""
import ldap import ldap
from django_auth_ldap.config import LDAPSearch from django_auth_ldap.config import LDAPSearch
import environ import environ
from pathlib import Path from pathlib import Path
# ***************读取LDAP的.env文件配置*************** # # ***************读取LDAP的.env文件配置*************** #
env_file = '.env' env_file = '.env'
env = environ.Env() env = environ.Env()
env.read_env(env_file=Path(__file__).resolve().parent.parent / env_file) env.read_env(env_file=Path(__file__).resolve().parent.parent / env_file)
# ================================================= # # ================================================= #
# *************** mysql数据库 配置 *************** # # *************** mysql数据库 配置 *************** #
# ================================================= # # ================================================= #
# 数据库地址 # 数据库地址
DATABASE_HOST = "127.0.0.1" DATABASE_HOST = "127.0.0.1"
# 数据库端口 # 数据库端口
DATABASE_PORT = 3307 # 生成环境配置 DATABASE_PORT = 3306 # 生成环境配置-注意打包时务必需改为3307!!!!!!
# 数据库用户名 # 数据库用户名
DATABASE_USER = "root" DATABASE_USER = "root"
# 数据库密码 # 数据库密码
DATABASE_PASSWORD = "root" DATABASE_PASSWORD = "root"
# 数据库名 # 数据库名
DATABASE_NAME = "chengdu_test_plant_v1" DATABASE_NAME = "chengdu_test_plant_v1"
# ================================================= # # ================================================= #
# ******************** celery配置 **************** # # ******************** celery配置 **************** #
# ================================================= # # ================================================= #
CELERY_BROKER_URL = "redis://127.0.0.1:6379/0" CELERY_BROKER_URL = "redis://127.0.0.1:6379/0"
CELERY_RESULT_BACKEND = "redis://127.0.0.1:6379/1" CELERY_RESULT_BACKEND = "redis://127.0.0.1:6379/1"
CELERY_ENABLE_UTC = False CELERY_ENABLE_UTC = False
CELERY_TIME_ZONE = "Asia/Shanghai" CELERY_TIME_ZONE = "Asia/Shanghai"
CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24 # 任务过期时间 CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24 # 任务过期时间
CELERY_REUSLT_SERIALIZER = "json" # celery结果序列化,接受mime类型任务序列化形式 CELERY_REUSLT_SERIALIZER = "json" # celery结果序列化,接受mime类型任务序列化形式
CELERY_ACCEPT_CONTENT = ['application/json'] CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json' CELERY_TASK_SERIALIZER = 'json'
DJANGO_CELERY_BEAT_TZ_AWARE = False DJANGO_CELERY_BEAT_TZ_AWARE = False
CELERY_WORKER_CONCURRENCY = 5 # 并发数量 CELERY_WORKER_CONCURRENCY = 5 # 并发数量
CELERY_MAX_TASKS_PER_CHILD = 10 # 每worker最多执行5个任务自动销毁 CELERY_MAX_TASKS_PER_CHILD = 10 # 每worker最多执行5个任务自动销毁
# ================================================= # # ================================================= #
# ****************** 其他 配置 ****************** # # ****************** 其他 配置 ****************** #
# ================================================= # # ================================================= #
ALLOWED_HOSTS = ["*"] # 线上环境设置 ALLOWED_HOSTS = ["*"] # 线上环境设置
LOGIN_NO_CAPTCHA_AUTH = True # 登录接口 /api/token/ 是否需要验证码认证,用于测试,正式环境建议取消 LOGIN_NO_CAPTCHA_AUTH = True # 登录接口 /api/token/ 是否需要验证码认证,用于测试,正式环境建议取消
ENABLE_LOGIN_ANALYSIS_LOG = True # 启动登录详细概略获取(通过调用api获取ip详细地址) ENABLE_LOGIN_ANALYSIS_LOG = True # 启动登录详细概略获取(通过调用api获取ip详细地址)
# ================================================= # # ================================================= #
# *************** 接口throttle配置 *************** # # *************** 接口throttle配置 *************** #
# ================================================= # # ================================================= #
# ================================================= # # ================================================= #
# *************** LDAP认证配置 *************** # # *************** LDAP认证配置 *************** #
# ================================================= # # ================================================= #
AUTHENTICATION_BACKENDS = [ AUTHENTICATION_BACKENDS = [
'django_auth_ldap.backend.LDAPBackend', 'django_auth_ldap.backend.LDAPBackend',
'django.contrib.auth.backends.ModelBackend', 'django.contrib.auth.backends.ModelBackend',
] ]
# ldap连接配置 # ldap连接配置
AUTH_LDAP_SERVER_URI = env('AUTH_LDAP_SERVER_URI', default='ldap://dns.paisat.cn:389') AUTH_LDAP_SERVER_URI = env('AUTH_LDAP_SERVER_URI', default='ldap://dns.paisat.cn:389')
# 绑定的DN,注意大小写敏感AdministratorUsers # 绑定的DN,注意大小写敏感AdministratorUsers
AUTH_LDAP_BIND_DN = env('AUTH_LDAP_BIND_DN', default="CN=Administrator,CN=Users,DC=sstc,DC=ctu") AUTH_LDAP_BIND_DN = env('AUTH_LDAP_BIND_DN', default="CN=Administrator,CN=Users,DC=sstc,DC=ctu")
# 管理员密码-生产环境 # 管理员密码-生产环境
AUTH_LDAP_BIND_PASSWORD = env('AUTH_LDAP_BIND_PASSWORD', default="WXWX2019!!!!!!") AUTH_LDAP_BIND_PASSWORD = env('AUTH_LDAP_BIND_PASSWORD', default="WXWX2019!!!!!!")
AUTH_LDAP_USER_SEARCH = LDAPSearch( AUTH_LDAP_USER_SEARCH = LDAPSearch(
env('BASE_DN', default='OU=all,DC=sstc,DC=ctu'), env('BASE_DN', default='OU=all,DC=sstc,DC=ctu'),
ldap.SCOPE_SUBTREE, env('FILTER_STR', default='(sAMAccountName=%(user)s)') ldap.SCOPE_SUBTREE, env('FILTER_STR', default='(sAMAccountName=%(user)s)')
) )
# 如果ldap服务器是Windows的AD需要配置上如下选项 # 如果ldap服务器是Windows的AD需要配置上如下选项
AUTH_LDAP_CONNECTION_OPTIONS = { AUTH_LDAP_CONNECTION_OPTIONS = {
ldap.OPT_DEBUG_LEVEL: 1, ldap.OPT_DEBUG_LEVEL: 1,
ldap.OPT_REFERRALS: 0, ldap.OPT_REFERRALS: 0,
} }
# 每次LDAP认证后进行数据库更新不包含密码 # 每次LDAP认证后进行数据库更新不包含密码
AUTH_LDAP_ALWAYS_UPDATE_USER = True AUTH_LDAP_ALWAYS_UPDATE_USER = True
# 看看下面是否需要password字段 # 看看下面是否需要password字段
AUTH_LDAP_USER_ATTR_MAP = { AUTH_LDAP_USER_ATTR_MAP = {
"username": "sAMAccountName", "username": "sAMAccountName",
"name": "name", "name": "name",
"email": "mail", "email": "mail",
} }
# ================================================= # # ================================================= #
# *************** ...........配置 *************** # # *************** ...........配置 *************** #
# ================================================= # # ================================================= #

View File

@@ -0,0 +1,2 @@
[WARNING][2026-04-17 14:20:04,514][logger.py:25][回归测试记录模块][字典数据缺失]片段:字典数据runtime数据缺失请检查相应数据是否存在
[WARNING][2026-04-17 14:20:04,518][logger.py:25][回归测试记录模块][字典数据缺失]片段:字典数据devplant数据缺失请检查相应数据是否存在

View File

@@ -322,3 +322,690 @@ Traceback (most recent call last):
pic_nodes = new_element.xpath('.//pic:pic', namespaces=nsmap) pic_nodes = new_element.xpath('.//pic:pic', namespaces=nsmap)
TypeError: BaseOxmlElement.xpath() got an unexpected keyword argument 'namespaces' TypeError: BaseOxmlElement.xpath() got an unexpected keyword argument 'namespaces'
[ERROR][2026-04-16 17:21:20,341][log.py:249]Internal Server Error: /api/documentUpload/file [ERROR][2026-04-16 17:21:20,341][log.py:249]Internal Server Error: /api/documentUpload/file
[WARNING][2026-04-17 13:45:31,769][log.py:249]Unauthorized: /api/system/getInfo
[WARNING][2026-04-17 13:45:31,835][log.py:249]Unauthorized: /api/system/logout
[WARNING][2026-04-17 13:45:36,826][backend.py:91]Caught LDAPError looking up user: SERVER_DOWN({'result': -1, 'desc': "Can't contact LDAP server", 'ctrls': []})
[WARNING][2026-04-17 14:20:04,514][logger.py:25][回归测试记录模块][字典数据缺失]片段:字典数据runtime数据缺失请检查相应数据是否存在
[WARNING][2026-04-17 14:20:04,518][logger.py:25][回归测试记录模块][字典数据缺失]片段:字典数据devplant数据缺失请检查相应数据是否存在
[WARNING][2026-04-17 16:18:06,060][operation.py:136]"PUT - TestDemandController[update_testDemand] /api/project/testDemand/update/670" (1406, "Data too long for column 'adequacy' at row 1")
[ERROR][2026-04-17 16:18:06,060][errors.py:131](1406, "Data too long for column 'adequacy' at row 1")
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
MySQLdb.DataError: (1406, "Data too long for column 'adequacy' at row 1")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner
return func(*args, **kwds)
File "E:\pycharmProjects\cdtestplant_v1\apps\project\controllers\testDemand.py", line 270, in update_testDemand
testDemand_qs.save()
~~~~~~~~~~~~~~~~~~^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 874, in save
self.save_base(
~~~~~~~~~~~~~~^
using=using,
^^^^^^^^^^^^
...<2 lines>...
update_fields=update_fields,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 966, in save_base
updated = self._save_table(
raw,
...<4 lines>...
update_fields,
)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1110, in _save_table
results = self._do_update(
base_qs,
...<5 lines>...
returning_fields,
)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1213, in _do_update
return filtered._update(values, returning_fields)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\query.py", line 1327, in _update
return query.get_compiler(self.db).execute_returning_sql(returning_fields)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\sql\compiler.py", line 2140, in execute_returning_sql
row_count = self.execute_sql(ROW_COUNT)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\sql\compiler.py", line 2111, in execute_sql
row_count = super().execute_sql(result_type)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1624, in execute_sql
cursor.execute(sql, params)
~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 122, in execute
return super().execute(sql, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute
return self._execute_with_wrappers(
~~~~~~~~~~~~~~~~~~~~~~~~~~~^
sql, params, many=False, executor=self._execute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers
return executor(sql, params, many, context)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute
with self.db.wrap_database_errors:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\utils.py", line 94, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
django.db.utils.DataError: (1406, "Data too long for column 'adequacy' at row 1")
[ERROR][2026-04-17 16:18:06,071][log.py:249]Internal Server Error: /api/project/testDemand/update/670
[WARNING][2026-04-17 16:35:01,341][log.py:249]Bad Request: /api/testmanage/project/save
[WARNING][2026-04-17 16:45:59,963][log.py:249]Bad Request: /api/testmanage/project/save
[WARNING][2026-04-17 16:46:01,209][log.py:249]Bad Request: /api/testmanage/project/save
[WARNING][2026-04-17 17:01:10,991][log.py:249]Bad Request: /api/testmanage/project/save
[WARNING][2026-04-20 09:31:28,826][log.py:249]Unauthorized: /api/system/getInfo
[WARNING][2026-04-20 09:31:28,893][log.py:249]Unauthorized: /api/system/logout
[WARNING][2026-04-20 09:31:36,102][backend.py:91]Caught LDAPError looking up user: SERVER_DOWN({'result': -1, 'desc': "Can't contact LDAP server", 'ctrls': []})
[ERROR][2026-04-20 09:34:09,062][log.py:249]Internal Server Error: /api/project/testDemand/save
[ERROR][2026-04-20 09:34:10,386][log.py:249]Internal Server Error: /api/project/testDemand/save
[ERROR][2026-04-20 09:34:10,841][log.py:249]Internal Server Error: /api/project/testDemand/save
[WARNING][2026-04-20 10:25:04,532][operation.py:136]"GET - GenerateControllerDG[create_static_hard] /api/generate/create/static_hard" ('All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters',)
[ERROR][2026-04-20 10:25:04,532][errors.py:131]All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 567, in create_static_hard
res = self.uniform_static_dynamic_response(id, '静态硬件和固件项_2.docx', '静态硬件和固件项.docx', StaticSoftHardware)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 535, in uniform_static_dynamic_response
subdoc = cls.create_table_context(table_data, doc)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 498, in create_table_context
cell.text = cell.text.replace("\n", "\a")
^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\table.py", line 284, in text
r.text = text
^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 143, in text
_RunContentAppender.append_to_run_from_text(self, text)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 279, in append_to_run_from_text
appender.add_text(text)
~~~~~~~~~~~~~~~~~^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 285, in add_text
self.flush()
~~~~~~~~~~^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 306, in flush
self._r.add_t(text)
~~~~~~~~~~~~~^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 42, in add_t
t = self._add_t(text=text)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\xmlchemy.py", line 288, in _add_child
setattr(child, key, value)
~~~~~~~^^^^^^^^^^^^^^^^^^^
File "src/lxml/etree.pyx", line 1168, in lxml.etree._Element.text.__set__
File "src/lxml/apihelpers.pxi", line 763, in lxml.etree._setNodeText
File "src/lxml/apihelpers.pxi", line 751, in lxml.etree._createTextNode
File "src/lxml/apihelpers.pxi", line 1556, in lxml.etree._utf8
ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters
[ERROR][2026-04-20 10:25:04,710][log.py:249]Internal Server Error: /api/generate/create/static_hard
[WARNING][2026-04-20 10:25:26,146][operation.py:136]"GET - GenerateControllerDG[create_static_hard] /api/generate/create/static_hard" ('All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters',)
[ERROR][2026-04-20 10:25:26,150][errors.py:131]All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 567, in create_static_hard
res = self.uniform_static_dynamic_response(id, '静态硬件和固件项_2.docx', '静态硬件和固件项.docx', StaticSoftHardware)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 535, in uniform_static_dynamic_response
subdoc = cls.create_table_context(table_data, doc)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 498, in create_table_context
cell.text = cell.text.replace("\n", "\a")
^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\table.py", line 284, in text
r.text = text
^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 143, in text
_RunContentAppender.append_to_run_from_text(self, text)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 279, in append_to_run_from_text
appender.add_text(text)
~~~~~~~~~~~~~~~~~^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 285, in add_text
self.flush()
~~~~~~~~~~^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 306, in flush
self._r.add_t(text)
~~~~~~~~~~~~~^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 42, in add_t
t = self._add_t(text=text)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\xmlchemy.py", line 288, in _add_child
setattr(child, key, value)
~~~~~~~^^^^^^^^^^^^^^^^^^^
File "src/lxml/etree.pyx", line 1168, in lxml.etree._Element.text.__set__
File "src/lxml/apihelpers.pxi", line 763, in lxml.etree._setNodeText
File "src/lxml/apihelpers.pxi", line 751, in lxml.etree._createTextNode
File "src/lxml/apihelpers.pxi", line 1556, in lxml.etree._utf8
ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters
[ERROR][2026-04-20 10:25:26,215][log.py:249]Internal Server Error: /api/generate/create/static_hard
[WARNING][2026-04-20 10:25:46,224][operation.py:136]"GET - GenerateControllerDG[create_static_hard] /api/generate/create/static_hard" ('All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters',)
[ERROR][2026-04-20 10:25:46,224][errors.py:131]All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 565, in create_static_hard
res = self.uniform_static_dynamic_response(id, '静态硬件和固件项_2.docx', '静态硬件和固件项.docx', StaticSoftHardware)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 533, in uniform_static_dynamic_response
subdoc = cls.create_table_context(table_data, doc)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 496, in create_table_context
cell.text = table_data[row][col - 1].replace("\n", "\a")
^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\table.py", line 284, in text
r.text = text
^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 143, in text
_RunContentAppender.append_to_run_from_text(self, text)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 279, in append_to_run_from_text
appender.add_text(text)
~~~~~~~~~~~~~~~~~^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 285, in add_text
self.flush()
~~~~~~~~~~^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 306, in flush
self._r.add_t(text)
~~~~~~~~~~~~~^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\text\run.py", line 42, in add_t
t = self._add_t(text=text)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docx\oxml\xmlchemy.py", line 288, in _add_child
setattr(child, key, value)
~~~~~~~^^^^^^^^^^^^^^^^^^^
File "src/lxml/etree.pyx", line 1168, in lxml.etree._Element.text.__set__
File "src/lxml/apihelpers.pxi", line 763, in lxml.etree._setNodeText
File "src/lxml/apihelpers.pxi", line 751, in lxml.etree._createTextNode
File "src/lxml/apihelpers.pxi", line 1556, in lxml.etree._utf8
ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters
[ERROR][2026-04-20 10:25:46,266][log.py:249]Internal Server Error: /api/generate/create/static_hard
[WARNING][2026-04-20 10:34:26,463][operation.py:136]"POST - DesignController[create_design] /api/project/designDemand/save" (1406, "Data too long for column 'protocal' at row 1")
[ERROR][2026-04-20 10:34:26,463][errors.py:131](1406, "Data too long for column 'protocal' at row 1")
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
MySQLdb.DataError: (1406, "Data too long for column 'protocal' at row 1")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner
return func(*args, **kwds)
File "E:\pycharmProjects\cdtestplant_v1\apps\project\controllers\design.py", line 100, in create_design
qs = Design.objects.create(**asert_dict)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\query.py", line 669, in create
obj.save(force_insert=True, using=self.db)
~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 874, in save
self.save_base(
~~~~~~~~~~~~~~^
using=using,
^^^^^^^^^^^^
...<2 lines>...
update_fields=update_fields,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 966, in save_base
updated = self._save_table(
raw,
...<4 lines>...
update_fields,
)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1169, in _save_table
results = self._do_insert(
cls._base_manager, using, insert_fields, returning_fields, raw
)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1220, in _do_insert
return manager._insert(
~~~~~~~~~~~~~~~^
[self],
^^^^^^^
...<3 lines>...
raw=raw,
^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\query.py", line 1918, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1925, in execute_sql
cursor.execute(sql, params)
~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 122, in execute
return super().execute(sql, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute
return self._execute_with_wrappers(
~~~~~~~~~~~~~~~~~~~~~~~~~~~^
sql, params, many=False, executor=self._execute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers
return executor(sql, params, many, context)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute
with self.db.wrap_database_errors:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\utils.py", line 94, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
django.db.utils.DataError: (1406, "Data too long for column 'protocal' at row 1")
[ERROR][2026-04-20 10:34:26,484][log.py:249]Internal Server Error: /api/project/designDemand/save
[WARNING][2026-04-20 10:35:26,599][operation.py:136]"POST - DesignController[create_design] /api/project/designDemand/save" (1406, "Data too long for column 'protocal' at row 1")
[ERROR][2026-04-20 10:35:26,599][errors.py:131](1406, "Data too long for column 'protocal' at row 1")
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
MySQLdb.DataError: (1406, "Data too long for column 'protocal' at row 1")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner
return func(*args, **kwds)
File "E:\pycharmProjects\cdtestplant_v1\apps\project\controllers\design.py", line 100, in create_design
qs = Design.objects.create(**asert_dict)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\query.py", line 669, in create
obj.save(force_insert=True, using=self.db)
~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 874, in save
self.save_base(
~~~~~~~~~~~~~~^
using=using,
^^^^^^^^^^^^
...<2 lines>...
update_fields=update_fields,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 966, in save_base
updated = self._save_table(
raw,
...<4 lines>...
update_fields,
)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1169, in _save_table
results = self._do_insert(
cls._base_manager, using, insert_fields, returning_fields, raw
)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1220, in _do_insert
return manager._insert(
~~~~~~~~~~~~~~~^
[self],
^^^^^^^
...<3 lines>...
raw=raw,
^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\query.py", line 1918, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1925, in execute_sql
cursor.execute(sql, params)
~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 122, in execute
return super().execute(sql, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute
return self._execute_with_wrappers(
~~~~~~~~~~~~~~~~~~~~~~~~~~~^
sql, params, many=False, executor=self._execute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers
return executor(sql, params, many, context)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute
with self.db.wrap_database_errors:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\utils.py", line 94, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
django.db.utils.DataError: (1406, "Data too long for column 'protocal' at row 1")
[ERROR][2026-04-20 10:35:26,608][log.py:249]Internal Server Error: /api/project/designDemand/save
[WARNING][2026-04-20 10:35:27,464][operation.py:136]"POST - DesignController[create_design] /api/project/designDemand/save" (1406, "Data too long for column 'protocal' at row 1")
[ERROR][2026-04-20 10:35:27,464][errors.py:131](1406, "Data too long for column 'protocal' at row 1")
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
MySQLdb.DataError: (1406, "Data too long for column 'protocal' at row 1")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner
return func(*args, **kwds)
File "E:\pycharmProjects\cdtestplant_v1\apps\project\controllers\design.py", line 100, in create_design
qs = Design.objects.create(**asert_dict)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\query.py", line 669, in create
obj.save(force_insert=True, using=self.db)
~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 874, in save
self.save_base(
~~~~~~~~~~~~~~^
using=using,
^^^^^^^^^^^^
...<2 lines>...
update_fields=update_fields,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 966, in save_base
updated = self._save_table(
raw,
...<4 lines>...
update_fields,
)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1169, in _save_table
results = self._do_insert(
cls._base_manager, using, insert_fields, returning_fields, raw
)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1220, in _do_insert
return manager._insert(
~~~~~~~~~~~~~~~^
[self],
^^^^^^^
...<3 lines>...
raw=raw,
^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\query.py", line 1918, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1925, in execute_sql
cursor.execute(sql, params)
~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 122, in execute
return super().execute(sql, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute
return self._execute_with_wrappers(
~~~~~~~~~~~~~~~~~~~~~~~~~~~^
sql, params, many=False, executor=self._execute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers
return executor(sql, params, many, context)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute
with self.db.wrap_database_errors:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\utils.py", line 94, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
django.db.utils.DataError: (1406, "Data too long for column 'protocal' at row 1")
[ERROR][2026-04-20 10:35:27,473][log.py:249]Internal Server Error: /api/project/designDemand/save
[WARNING][2026-04-20 10:35:27,981][operation.py:136]"POST - DesignController[create_design] /api/project/designDemand/save" (1406, "Data too long for column 'protocal' at row 1")
[ERROR][2026-04-20 10:35:27,981][errors.py:131](1406, "Data too long for column 'protocal' at row 1")
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
MySQLdb.DataError: (1406, "Data too long for column 'protocal' at row 1")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner
return func(*args, **kwds)
File "E:\pycharmProjects\cdtestplant_v1\apps\project\controllers\design.py", line 100, in create_design
qs = Design.objects.create(**asert_dict)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\query.py", line 669, in create
obj.save(force_insert=True, using=self.db)
~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 874, in save
self.save_base(
~~~~~~~~~~~~~~^
using=using,
^^^^^^^^^^^^
...<2 lines>...
update_fields=update_fields,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 966, in save_base
updated = self._save_table(
raw,
...<4 lines>...
update_fields,
)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1169, in _save_table
results = self._do_insert(
cls._base_manager, using, insert_fields, returning_fields, raw
)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1220, in _do_insert
return manager._insert(
~~~~~~~~~~~~~~~^
[self],
^^^^^^^
...<3 lines>...
raw=raw,
^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\query.py", line 1918, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1925, in execute_sql
cursor.execute(sql, params)
~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 122, in execute
return super().execute(sql, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute
return self._execute_with_wrappers(
~~~~~~~~~~~~~~~~~~~~~~~~~~~^
sql, params, many=False, executor=self._execute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers
return executor(sql, params, many, context)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute
with self.db.wrap_database_errors:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\utils.py", line 94, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
django.db.utils.DataError: (1406, "Data too long for column 'protocal' at row 1")
[ERROR][2026-04-20 10:35:27,991][log.py:249]Internal Server Error: /api/project/designDemand/save
[WARNING][2026-04-20 10:45:28,053][log.py:249]Bad Request: /api/project/editDesignDemand/4028
[ERROR][2026-04-20 17:05:17,173][log.py:249]Internal Server Error: /api/project/case/create_by_demand

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More