日常修复内容
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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))
|
||||||
|
|||||||
Binary file not shown.
@@ -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
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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')
|
||||||
|
|||||||
@@ -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='运行环境'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/project/migrations/0031_alter_testdemand_adequacy.py
Normal file
18
apps/project/migrations/0031_alter_testdemand_adequacy.py
Normal 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='充分条件'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/project/migrations/0032_alter_design_protocal.py
Normal file
18
apps/project/migrations/0032_alter_design_protocal.py
Normal 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='接口数据'),
|
||||||
|
),
|
||||||
|
]
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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")
|
||||||
|
|||||||
@@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
166
conf/env.py
166
conf/env.py
@@ -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,注意大小写敏感Administrator,Users
|
# 绑定的DN,注意大小写敏感Administrator,Users
|
||||||
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",
|
||||||
}
|
}
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
# *************** ...........配置 *************** #
|
# *************** ...........配置 *************** #
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
|
|||||||
@@ -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数据缺失,请检查相应数据是否存在
|
||||||
|
|||||||
687
logs/root_log
687
logs/root_log
@@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
media/R2601/final_seitai/测评报告.docx
Normal file
BIN
media/R2601/final_seitai/测评报告.docx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
media/R2601/final_seitai/第二轮回归测试记录.docx
Normal file
BIN
media/R2601/final_seitai/第二轮回归测试记录.docx
Normal file
Binary file not shown.
BIN
media/R2601/final_seitai/第二轮回归测试说明.docx
Normal file
BIN
media/R2601/final_seitai/第二轮回归测试说明.docx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
Reference in New Issue
Block a user