Compare commits
7
Commits
2c969c7b9c
..
test
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95714309c9 | ||
|
|
6bf636e76b | ||
|
|
33a6ab75da | ||
|
|
519e9b180a | ||
|
|
962a793d13 | ||
|
|
60d4066b99 | ||
|
|
d9a41a8738 |
+16
@@ -0,0 +1,16 @@
|
||||
.venv/
|
||||
.idea
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.pytest_cache/
|
||||
.mypy_cache/
|
||||
.ruff_cache/
|
||||
tests/
|
||||
.git/
|
||||
.github/
|
||||
*.md
|
||||
!README.md
|
||||
.env
|
||||
.env.*
|
||||
Dockerfile
|
||||
|
||||
Generated
-10
@@ -1,10 +0,0 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 已忽略包含查询文件的默认文件夹
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
Generated
-12
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="@localhost" uuid="f010600d-8f20-492b-bab2-be2a925ffc75">
|
||||
<driver-ref>mysql.8</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:mysql://localhost:3306</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPep8Inspection" enabled="true" level="INFORMATION" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="E116" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
Generated
-12
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="E:\anaconda3\envs\newai0824" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="PackageRequirementsSettings" />
|
||||
<component name="PyDocumentationSettings" />
|
||||
<component name="ReSTService" />
|
||||
<component name="TestRunnerService" />
|
||||
</module>
|
||||
Generated
-7
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="uv (student_manage_system)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
Generated
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/student_manage_system.iml" filepath="$PROJECT_DIR$/.idea/student_manage_system.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.10" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
3.13
|
||||
@@ -1 +1,286 @@
|
||||
# 学生管理系统
|
||||
# 教培系统架构设计与开发
|
||||
|
||||
本项目旨在开发一个基于FastAPI的学生管理系统,提供**学生基本信息管理、考核成绩管理和就业管理**三大核心功能模块。
|
||||
|
||||
系统将采用RESTful API设计,支持前后端分离架构。
|
||||
|
||||
|
||||
|
||||
## 需求分期
|
||||
|
||||
团队对需求管理按照模块化解耦拆分开发,按照三个阶段开发
|
||||
|
||||
1. 基础需求:按照开发任务,完成5 + 1 统计模块的开发
|
||||
|
||||
2. 特色需求: todo: 每个人补充一下自己对本模块的理解
|
||||
|
||||
- 数据源配置
|
||||
|
||||
- 鉴权管理
|
||||
|
||||
- 添加部门管理,顾问管理模块
|
||||
|
||||
- 添加用户认证模块
|
||||
|
||||
- 开发前端应用
|
||||
|
||||
- 开发更多的分析查询接口
|
||||
|
||||
- 增加AI智能体和知识库开发
|
||||
|
||||
3. 脚手架集成
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 第一阶段 - 基础需求
|
||||
|
||||
按照开发任务,完成5 + 1 统计模块的开发
|
||||
|
||||
- 学生
|
||||
- 班级
|
||||
- 老师
|
||||
- 成绩
|
||||
- 就业
|
||||
- 统计分析
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 第二阶段 - 特色需求
|
||||
|
||||
- 数据源配置
|
||||
|
||||
- 鉴权管理
|
||||
|
||||
- 添加部门管理,顾问管理模块
|
||||
|
||||
- 添加用户认证模块
|
||||
|
||||
- 开发前端应用
|
||||
|
||||
- 开发更多的分析查询接口
|
||||
|
||||
- 增加AI智能体和知识库开发
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 第三阶段 - 脚手架集成
|
||||
|
||||
核心组件
|
||||
|
||||
- 服务状态监控 - utc时区[还有哪些可替代?]
|
||||
- db ,中间件等组件是否活跃
|
||||
- 自身服务是否活跃
|
||||
- 认证模块: oauth2_scheme
|
||||
-
|
||||
-
|
||||
|
||||
|
||||
|
||||
## 业务拆分
|
||||
|
||||
> 业务范围划分
|
||||
>
|
||||
> - 实体
|
||||
> - 学生基本信息管理
|
||||
> - 考核成绩管理
|
||||
> - 就业管理
|
||||
> - 班级
|
||||
> - 老师
|
||||
> - 统计分析
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 数据架构设计
|
||||
|
||||
数据关系
|
||||
|
||||
- 学生:班级 = N: 1, 班级:老师 = 1 : 1 / [N:1], 学生: 成绩 = 1:N , 学生:就业 = 1:1,
|
||||
- 统计分析:
|
||||
|
||||
|
||||
|
||||
表结构优化
|
||||
|
||||
- 索引设置
|
||||
-
|
||||
|
||||
|
||||
|
||||
```sql
|
||||
create database student_management_system;
|
||||
use student_management_system;
|
||||
|
||||
-- students
|
||||
create table if not exists students(
|
||||
id int auto_increment primary key,
|
||||
snum int not null comment '学生编号',
|
||||
sname varchar(30) not null,
|
||||
age int not null,
|
||||
sex int not null,
|
||||
|
||||
home_place varchar(50) null comment '家乡',
|
||||
college varchar(50) null comment '毕业院校',
|
||||
specialty varchar(50) null comment '专业',
|
||||
enrollment_time datetime null comment '入学时间',
|
||||
graduate_time datetime null comment '毕业时间',
|
||||
education varchar(50) null comment '学历',
|
||||
|
||||
class_id int not null,
|
||||
|
||||
advisor_id int null comment '顾问id',
|
||||
advisor_num int null comment '顾问编号',
|
||||
|
||||
-- 通用字段
|
||||
create_time datetime not null,
|
||||
update_time datetime not null,
|
||||
is_detleted int not null comment '0 未删除,1'
|
||||
);
|
||||
|
||||
-- teachers
|
||||
create table if not exists teachers(
|
||||
id int auto_increment primary key,
|
||||
tnum int not null comment '老师编号',
|
||||
tname int not null,
|
||||
age int not null,
|
||||
sex int not null,
|
||||
|
||||
home_place varchar(50) null comment '家乡',
|
||||
college varchar(50) null comment '毕业院校',
|
||||
specialty varchar(50) null comment '专业',
|
||||
enrollment_time datetime null comment '入学时间',
|
||||
graduate_time datetime null comment '毕业时间',
|
||||
education varchar(50) null comment '学历',
|
||||
|
||||
-- 额外信息:工作经验/教学评级 ,教学方向:应用,项目,算法;
|
||||
work_experience text null comment '工作经验',
|
||||
coach_area text null comment '教学方向:应用,项目,算法',
|
||||
|
||||
-- 通用字段
|
||||
create_time datetime not null,
|
||||
update_time datetime not null,
|
||||
is_detleted int not null comment '0 未删除,1'
|
||||
);
|
||||
|
||||
|
||||
-- classes
|
||||
create table if not exists classes(
|
||||
id int auto_increment primary key,
|
||||
class_num int not null comment '班级编号',
|
||||
class_start_time datetime null comment '开课时间',
|
||||
head_teacher_id int null comment '班主任',
|
||||
head_teacher_num int null comment '班主任编号',
|
||||
|
||||
coach_teacher_id int null comment '授课老师',
|
||||
coach_teacher_num int null comment '授课老师编号',
|
||||
|
||||
tutor_teacher_id int null comment '助教老师',
|
||||
tutor_teacher_num int null comment '助教老师编号',
|
||||
|
||||
-- 通用字段
|
||||
create_time datetime not null,
|
||||
update_time datetime not null,
|
||||
is_detleted int not null comment '0 未删除,1'
|
||||
);
|
||||
|
||||
|
||||
-- scores
|
||||
create table if not exists scores(
|
||||
id int auto_increment primary key,
|
||||
sid int not null,
|
||||
snum int not null,
|
||||
score_num int not null comment '考核序次',
|
||||
score decimal(10,2) not null,
|
||||
|
||||
-- 通用字段
|
||||
create_time datetime not null,
|
||||
update_time datetime not null,
|
||||
is_detleted int not null comment '0 未删除,1'
|
||||
);
|
||||
|
||||
|
||||
-- employment
|
||||
create table if not exists employment(
|
||||
id int auto_increment primary key,
|
||||
sid int not null,
|
||||
snum int not null,
|
||||
sname varchar(30) not null,
|
||||
class_id int not null,
|
||||
class_num int not null comment '班级编号',
|
||||
|
||||
employment_open_time datetime null comment '就业开放时间',
|
||||
offer_recived_time datetime null comment 'offer下发时间',
|
||||
employment_company varchar(50) null comment '就业公司',
|
||||
employment_salary decimal(10,2) null comment '就业薪资',
|
||||
|
||||
-- 通用字段
|
||||
create_time datetime not null,
|
||||
update_time datetime not null,
|
||||
is_detleted int not null comment '0 未删除,1'
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 技术架构设计
|
||||
|
||||
|
||||
|
||||
### 构建环境适配
|
||||
|
||||
```bash
|
||||
# uv 统一
|
||||
pip install uv
|
||||
uv init
|
||||
uv add fastapi[standard] pymsql sqlalchemy # 添加依赖
|
||||
|
||||
# 运行测试
|
||||
uv run uvicorn main:app --reload # uv run fastapi dev
|
||||
|
||||
# 其他平台: sync 同步即可
|
||||
uv sync
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 基础架构适配
|
||||
|
||||
- 后端框架:
|
||||
- web route / api docs / 数据校验 : FastAPI
|
||||
- ORM 框架: pymysql, sqlarchemy
|
||||
- 日志系统:loguru,
|
||||
-
|
||||
- 数据库:多数据源适配
|
||||
- dev : sqlite3
|
||||
- prod: MySQL, PG
|
||||
- 前端框架:
|
||||
- vue3
|
||||
-
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 脚手架设计
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
from fastapi import APIRouter,Depends,HTTPException
|
||||
from Teachers.schema import *
|
||||
from Teachers.database import *
|
||||
from Teachers.model.tea_model import *
|
||||
from Teachers.dao.tea_dao import *
|
||||
from Teachers.schema.tea_request import TeaRequest,NewTeaRequest
|
||||
from Teachers.schema.tea_response import TeaResponse
|
||||
|
||||
tea_api = APIRouter(tags=['老师相关接口'])
|
||||
|
||||
@tea_api.post('/tea',response_model=TeaResponse,summary='新增老师',description='输入新增的老师信息,除去姓名外可以为空')
|
||||
def add_tea(tea: NewTeaRequest,db=Depends(get_db)):
|
||||
r = add_tea_dao(tea.model_dump(),db)
|
||||
if not r:
|
||||
raise HTTPException(status_code=500,detail='添加失败!')
|
||||
return TeaResponse(totals=1,data=tea.model_dump())
|
||||
@tea_api.get('/tea',response_model=TeaResponse,summary='查询老师',description='任意选择输入的信息数量,不输入则查询全部老师')
|
||||
def get_tea(t:TeaRequest=Depends(),db=Depends(get_db)): #开启会话窗口
|
||||
r = get_tea_dao(t.model_dump(),db=db)
|
||||
if not r:
|
||||
raise HTTPException(status_code=404,detail='老师不存在')
|
||||
return TeaResponse(totals=len(r), data=r)
|
||||
@tea_api.delete('/tea/{id}',summary='删除老师',description='输入删除的老师id')
|
||||
def delete_tea(id:int|None,db=Depends(get_db)):
|
||||
r = delete_tea_dao(id,db)
|
||||
if not r:
|
||||
raise HTTPException(status_code=500,detail='删除失败!')
|
||||
return {'detail':'删除成功!'}
|
||||
|
||||
@tea_api.put('/tea/{id}',summary='修改老师信息',description='输入更改的信息,老师的姓名和性别不能为空,其余可以为空')
|
||||
def update_tea(id:int,tea:NewTeaRequest,db=Depends(get_db)):
|
||||
t = tea.model_dump(exclude_unset= True)
|
||||
r = update_tea_dao(id=id,update_data=t,db=db)
|
||||
if not r:
|
||||
raise HTTPException(status_code=404,detail='老师不存在')
|
||||
return {'detail':'修改成功'}
|
||||
@@ -1,72 +0,0 @@
|
||||
from Teachers.model.tea_model import Tea
|
||||
from datetime import datetime
|
||||
|
||||
#增加
|
||||
def add_tea_dao(t,db):
|
||||
try:
|
||||
t1 = Tea(**t)
|
||||
db.add(t1)
|
||||
except:
|
||||
db.rollback()
|
||||
return False
|
||||
else:
|
||||
db.commit()
|
||||
return True
|
||||
|
||||
#更新
|
||||
def add_tea_dao(t, db):
|
||||
try:
|
||||
t1 = Tea(**t)
|
||||
db.add(t1)
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
print('新增失败原因:', e)
|
||||
return False
|
||||
else:
|
||||
db.commit()
|
||||
return True
|
||||
|
||||
#查询
|
||||
def get_tea_dao(t,db):
|
||||
query = db.query(Tea).filter(Tea.is_delete == False)
|
||||
if t.get('id'):
|
||||
query = query.filter(Tea.id == t.get('id') )
|
||||
if t.get('name'):
|
||||
query = query.filter(Tea.name == t.get('name') )
|
||||
if t.get("sex"):
|
||||
query = query.filter(Tea.sex == t.get('sex') )
|
||||
if t.get('class_id'):
|
||||
query = query.filter(Tea.class_id == t.get('claa_id') )
|
||||
if t.get('sub'):
|
||||
query = query.filter(Tea.sub == t.get('sub') )
|
||||
if t.get('home_place'):
|
||||
query = query.filter(Tea.home_place == t.get('home_place') )
|
||||
if t.get('specialty'):
|
||||
query = query.filter(Tea.specialty == t.get('specialty') )
|
||||
if t.get('start_time'):
|
||||
query = query.filter(Tea.start_time == t.get('start_time') )
|
||||
if t. get('work_experience'):
|
||||
query = query.filter(Tea.work_experience == t.get('work_experience') )
|
||||
if t.get('education'):
|
||||
query = query.filter(Tea.education == t.get('education') )
|
||||
if t.get('college'):
|
||||
query = query.filter(Tea.collage == t.get('college') )
|
||||
r = query.all()
|
||||
return [{'id':i.id,'name':i.name,'class_id':i.class_id,'sub':i.sub,'tea.sex':i.sex,'home_place':i.home_place
|
||||
,'specialty':i.specialty,'start_time':i.start_time,'work_experience':i.work_experience,'college':i.college} for i in r]
|
||||
|
||||
#删除
|
||||
def delete_tea_dao(id,db):
|
||||
try:
|
||||
row = db.query(Tea).filter(Tea.id == id
|
||||
,Tea.is_delete == False
|
||||
).update({'is_delete':True,'delete_time':datetime.now()})
|
||||
except:
|
||||
db.rollback()
|
||||
row = 0
|
||||
return
|
||||
else:
|
||||
db.commit()
|
||||
return row
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
from sqlalchemy import *
|
||||
from sqlalchemy.orm import sessionmaker,declarative_base
|
||||
|
||||
db_tea = 'mysql+pymysql://root:123456@127.0.0.1:3306/student_manage_system?charset=utf8mb4'
|
||||
engine1 = create_engine(db_tea)
|
||||
|
||||
Base = declarative_base()
|
||||
Session = sessionmaker(bind=engine1
|
||||
,autoflush = False
|
||||
,autocommit = False)
|
||||
def get_db():
|
||||
db = Session()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
Base.metadata.create_all(engine1)
|
||||
@@ -1,16 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from Teachers.model.tea_model import *
|
||||
from api.tea_api import tea_api
|
||||
app = FastAPI()
|
||||
app.include_router(tea_api)
|
||||
|
||||
Base.metadata.create_all(engine1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run('main:app', host='0.0.0.0', port=55000)
|
||||
"""
|
||||
IPv4 地址 . . . . . . . . . . . . : 192.168.1.51
|
||||
子网掩码 . . . . . . . . . . . . : 255.255.255.0
|
||||
默认网关. . . . . . . . . . . . . : 192.168.1.1
|
||||
"""
|
||||
@@ -1,48 +0,0 @@
|
||||
from Teachers.database import *
|
||||
from datetime import datetime
|
||||
from sqlalchemy import *
|
||||
import enum
|
||||
|
||||
class Gender(str,enum.Enum):
|
||||
m = '男'
|
||||
f = '女'
|
||||
|
||||
class Tea(Base):
|
||||
__tablename__ = 'teachers'
|
||||
id = Column(Integer
|
||||
, primary_key=True
|
||||
,nullable=False
|
||||
,autoincrement=True
|
||||
,comment='id')
|
||||
name = Column(String(50)
|
||||
,nullable=False
|
||||
,comment='姓名')
|
||||
sex = Column(Enum(Gender),default='未知'
|
||||
,comment='性别')
|
||||
class_id = Column(Integer
|
||||
,nullable=False
|
||||
,comment='班级id')
|
||||
sub = Column(String(50)
|
||||
,nullable=False
|
||||
,comment='教学科目')
|
||||
home_place = Column(String(50)
|
||||
,comment='家乡')
|
||||
specialty = Column(String(50)
|
||||
,comment='专业')
|
||||
start_time = Column(DateTime,comment='入职时间')
|
||||
work_experience = Column(String(50)
|
||||
,comment='工作经验')
|
||||
education = Column(String(50)
|
||||
,comment='学历')
|
||||
collage = Column(String(50)
|
||||
,comment='毕业院校')
|
||||
create_date = Column(DateTime
|
||||
,default=datetime.now
|
||||
,comment='创建时间')
|
||||
update_date = Column(DateTime
|
||||
,onupdate=datetime.now
|
||||
,comment='更新时间')
|
||||
is_delete = Column(Boolean,default=False,comment='是否删除')
|
||||
delete_time = Column(DateTime)
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
from pydantic import BaseModel
|
||||
from Teachers.model.tea_model import *
|
||||
|
||||
#查询使用请求体
|
||||
class TeaRequest(BaseModel):
|
||||
id: int|None = None
|
||||
name: str|None = None
|
||||
sex: Gender|None = None
|
||||
class_id: int | None = None
|
||||
sub: str|None = None
|
||||
home_place: str|None = None
|
||||
collage: str|None = None
|
||||
education: str|None = None
|
||||
work_experience: str|None = None
|
||||
start_time: str|None = None
|
||||
specialty: str|None = None
|
||||
|
||||
|
||||
#更新、新增使用请求体(无法覆盖)
|
||||
class NewTeaRequest(BaseModel):
|
||||
name: str | None = None
|
||||
sex: Gender
|
||||
class_id: int | None = None
|
||||
sub: str | None = None
|
||||
home_place: str | None = None
|
||||
collage: str | None = None
|
||||
education: str | None = None
|
||||
work_experience: str | None = None
|
||||
start_time: datetime | None = None
|
||||
specialty: str | None = None
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
class TeaResponse(BaseModel):
|
||||
code: int = 200
|
||||
detail: str = 'OK'
|
||||
totals:int = 0
|
||||
data: str |dict|tuple|list
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/")
|
||||
def main():
|
||||
print("Hello from student-manage-system!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,12 @@
|
||||
[project]
|
||||
name = "student-manage-system"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"fastapi[standard]>=0.141.1",
|
||||
"pip>=26.2.1",
|
||||
"pymysql>=1.2.3",
|
||||
"sqlalchemy>=2.0.54",
|
||||
]
|
||||
Reference in New Issue
Block a user