Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89a10c598b | ||
|
|
da71b48a10 | ||
|
|
9173db07c4 | ||
|
|
65997d9c31 | ||
|
|
d28b4beff9 | ||
|
|
ff49a4ac20 | ||
|
|
ae8af02d1b | ||
|
|
8a4c769269 | ||
|
|
24fc2d8c89 | ||
|
|
ece3b235ec | ||
|
|
9f53b3389c | ||
|
|
e9e6aaa838 | ||
|
|
b898896686 | ||
|
|
78a9f1bdcb | ||
|
|
546bc68847 | ||
|
|
9692c0867d | ||
|
|
21317efe78 | ||
|
|
2ddd390682 | ||
|
|
ebbcd3f616 | ||
|
|
e79dc828bc | ||
|
|
9b490cb76a | ||
|
|
c1f0283792 | ||
|
|
42bcdcd6a6 | ||
|
|
8e2ca91117 | ||
|
|
a0831f25ec | ||
|
|
0b891e19d4 | ||
|
|
d7e1e4ab3b | ||
|
|
e6c92e254a | ||
|
|
02b5e31307 | ||
|
|
8c048d65e4 | ||
|
|
ebdfb9016b | ||
|
|
1d085867d6 | ||
|
|
59fe699940 | ||
|
|
03f0761974 | ||
|
|
de755c3c26 | ||
|
|
8a131c1b7b | ||
|
|
71aafe32e9 | ||
|
|
50b30d6eb0 | ||
|
|
343a4e1532 | ||
|
|
a96ee13276 | ||
|
|
f31743d670 | ||
|
|
0f7a0dba2f | ||
|
|
6d76d6af48 | ||
|
|
ddbdd3f041 | ||
|
|
e234cd66da |
+18
@@ -0,0 +1,18 @@
|
|||||||
|
# Python 缓存
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
|
||||||
|
# Python 虚拟环境
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
env/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# 系统垃圾
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
from fastapi import APIRouter,Depends,HTTPException
|
||||||
|
from schemas.class_schema import *
|
||||||
|
from core.database import get_db
|
||||||
|
from dao.class_dao import *
|
||||||
|
|
||||||
|
classes_router = APIRouter()
|
||||||
|
|
||||||
|
@classes_router.post('/',response_model=ClassResponse)
|
||||||
|
def post_classes(classes:ClassCreate,db=Depends(get_db)):
|
||||||
|
c = classes.model_dump()
|
||||||
|
r = post_classes_dao( c , db )
|
||||||
|
if r :
|
||||||
|
return ClassResponse( total=1,data=c )
|
||||||
|
else :
|
||||||
|
raise HTTPException(status_code=500,detail='添加失败,服务器繁忙,请稍后添加!')
|
||||||
|
|
||||||
|
|
||||||
|
@classes_router.put('/{id}',response_model=ClassResponse)
|
||||||
|
def put_classes(id:int,classes:ClassUpdate,db=Depends(get_db)):
|
||||||
|
updates = classes.model_dump( exclude_unset=True )
|
||||||
|
r = update_classes_dao( id , db , updates )
|
||||||
|
if r :
|
||||||
|
return ClassResponse( total=1,data=updates )
|
||||||
|
else :
|
||||||
|
raise HTTPException(status_code=500, detail='更新失败,该班级已不存在或服务器繁忙,请稍后更新!')
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#这是一个示例文件,确保api端口能被正常调用
|
||||||
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
example_router = APIRouter()
|
||||||
|
|
||||||
|
@example_router.get("/example")
|
||||||
|
def example():
|
||||||
|
return {'hello DoubaoTeam'}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
from fastapi import APIRouter,HTTPException,Depends
|
||||||
|
from DoubaoTeam.core.database import get_db
|
||||||
|
from DoubaoTeam.models.student import Student
|
||||||
|
from DoubaoTeam.models.score import Score
|
||||||
|
from DoubaoTeam.dao.statistics import *
|
||||||
|
from DoubaoTeam.schemas.common import SuccessResponse
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
|
||||||
|
statistics_router=APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@statistics_router.get("/scores/age-over-30",response_model=SuccessResponse)
|
||||||
|
def api_age_over_thirty(db:Session=Depends(get_db)):
|
||||||
|
try:
|
||||||
|
age_over_thirty_list=age_over_thirty(Student,db)
|
||||||
|
return SuccessResponse(status_code=200,msg=age_over_thirty_list)
|
||||||
|
except NoExist as e:
|
||||||
|
raise HTTPException(status_code=404,detail=str(e))
|
||||||
|
# 这边功能函数返回的是一个字典
|
||||||
|
@statistics_router.get("/classes/gender-count",response_model=SuccessResponse)
|
||||||
|
def api_gender_count(db:Session=Depends(get_db)):
|
||||||
|
try:
|
||||||
|
result = gender_count(Student,db)
|
||||||
|
return SuccessResponse(status_code=200,msg=result)
|
||||||
|
except NoExist as e:
|
||||||
|
raise HTTPException(status_code=404,detail=str(e))
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
from fastapi import APIRouter,Depends,HTTPException
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from dao.student import *
|
||||||
|
from schemas.student import StudentCreate
|
||||||
|
|
||||||
|
student_router = APIRouter()
|
||||||
|
|
||||||
|
@student_router.post("/student")
|
||||||
|
def create_student(request:StudentCreate,db:Session,create = Depends(create_students)):
|
||||||
|
d = request.model_dump()
|
||||||
|
r = create_students(d,db)
|
||||||
|
if not r:
|
||||||
|
raise HTTPException(status_code=500,detail='服务器繁忙,请稍后添加!')
|
||||||
|
return {'code':200,'detail':"添加学生成功"}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
"mysql+pymysql://root:123456@localhost/fastapi_db?charset=utf8mb4"
|
||||||
|
|
||||||
|
database_connect_user = 'root'
|
||||||
|
database_connect_password = '123456'
|
||||||
|
database_connect_ip = 'localhost'
|
||||||
|
database_connect_database_name = 'student_manager'
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
'''
|
||||||
|
1.此文件已经配置 engine 和 SessionLocal .
|
||||||
|
由于还没合库,需要自己去 /core/database 配置库名。默认为 student_manager
|
||||||
|
具体配置如下
|
||||||
|
用户:root
|
||||||
|
密码:123456
|
||||||
|
IP:localhost
|
||||||
|
库名:student_manager
|
||||||
|
|
||||||
|
2.如果还没开始建库,建库时统一将名称命名为 student_manager。
|
||||||
|
如果已经建库或在 models 目录写好Base函数,那先别提交分支,不然合并的时候会出问题,后天合库的时候再说。
|
||||||
|
|
||||||
|
3.在 /models 目录下写数据库对应类时,不要自己写Base = declarative_base(),
|
||||||
|
直接 from core.database import Base ,否则会出现 Base 不一致的情况,导致数据库无法创建表。
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.orm import sessionmaker,declarative_base
|
||||||
|
from core.config import (
|
||||||
|
database_connect_user,
|
||||||
|
database_connect_password,
|
||||||
|
database_connect_ip,
|
||||||
|
database_connect_database_name,
|
||||||
|
)
|
||||||
|
engine = create_engine( #engine负责连接mysql
|
||||||
|
f"mysql+pymysql://{database_connect_user}:{database_connect_password}@{database_connect_ip}/{database_connect_database_name}?charset=utf8mb4",
|
||||||
|
pool_size=50
|
||||||
|
)
|
||||||
|
SessionLocal = sessionmaker(bind=engine, autoflush=False,autocommit=False)
|
||||||
|
|
||||||
|
def get_db():
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
yield db
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
Base = declarative_base()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
from models.class_model import Classes
|
||||||
|
|
||||||
|
|
||||||
|
def post_classes_dao( c , db ):
|
||||||
|
try :
|
||||||
|
cc = Classes( **c )
|
||||||
|
db.add( cc )
|
||||||
|
except :
|
||||||
|
db.rollback()
|
||||||
|
return False
|
||||||
|
else :
|
||||||
|
db.commit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def update_classes_dao( class_id , db , updates ):
|
||||||
|
try :
|
||||||
|
db.query( Classes ).filter( Classes.id==class_id , Classes.is_deleted==0 ) .update( updates )
|
||||||
|
except :
|
||||||
|
db.rollback()
|
||||||
|
return False
|
||||||
|
else :
|
||||||
|
db.commit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
# def get_classes_dao( class_id , class_name , db ):
|
||||||
|
# try :
|
||||||
|
# r = db.query( Classes ).filter( Classes.id==class_id , Classes.is_deleted==0 ) .all()
|
||||||
|
# except :
|
||||||
|
# db.rollback()
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
from DoubaoTeam.schemas.statistics import NoExist
|
||||||
|
from sqlalchemy import func
|
||||||
|
|
||||||
|
#`GET /statistics/students/age-over-30`
|
||||||
|
#查询所有超过 30 岁的学员信息
|
||||||
|
|
||||||
|
def age_over_thirty(Student,db):
|
||||||
|
student_list=db.query(Student).filter(Student.age>=30).all()
|
||||||
|
if not student_list :
|
||||||
|
raise NoExist('无目标年龄大于30岁')
|
||||||
|
return student_list
|
||||||
|
|
||||||
|
def gender_count(Student,db):
|
||||||
|
result=db.query(Student.class_id,Student.gender,func.count(Student.id)).group_by(Student.class_id,Student.gender).all()
|
||||||
|
if not result :
|
||||||
|
raise NoExist('班里招点人吧,要倒闭了')
|
||||||
|
dict1 = {}
|
||||||
|
for i,j,k in result:
|
||||||
|
if i not in dict1 :
|
||||||
|
dict1[i]={'男':0,'女':0}
|
||||||
|
dict[i][j]+=k
|
||||||
|
return dict1
|
||||||
|
#查询每次考试成绩都在 80 分以上的学生编号、姓名和成绩
|
||||||
|
def score_over_eighty(Score,Student,db):
|
||||||
|
student_list=db.query(Student.id, Student.student_name)\
|
||||||
|
.join(Student,Score.student_id==Student.id).group_by(Student.student_no,Student.student_name)\
|
||||||
|
.having(func.min(Score.score)>80).all()
|
||||||
|
for i in student_list:
|
||||||
|
student_list2 = db.query(Student.student_no, Student.student_name,Score.score).join(Student,Score.student_id==Student.id).filter(i.id==Student.id).all()
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
from schemas.student import *
|
||||||
|
from core.database import get_db
|
||||||
|
from models.student import *
|
||||||
|
from utils.code_generator import generate_no
|
||||||
|
|
||||||
|
|
||||||
|
def create_students(d,db):
|
||||||
|
stu = Student(**d)
|
||||||
|
try:
|
||||||
|
db.add(stu)
|
||||||
|
generate_no("student_no", "STU", stu, db)
|
||||||
|
db.commit()
|
||||||
|
except:return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,31 @@
|
|||||||
|
from fastapi import FastAPI
|
||||||
|
from api.example import example_router
|
||||||
|
from middleware import log_middleware
|
||||||
|
from api.statistics import statistics_router
|
||||||
|
import uvicorn
|
||||||
|
from api.student import student_router
|
||||||
|
app = FastAPI()
|
||||||
|
app.middleware("http")(log_middleware)
|
||||||
|
|
||||||
|
#-------------朱婷婷--------------
|
||||||
|
from api.class_api import classes_router
|
||||||
|
app.include_router(classes_router,tags=['班级接口'],prefix="/classes")
|
||||||
|
|
||||||
|
#-------------李玉杰--------------
|
||||||
|
app.include_router(student_router)
|
||||||
|
#-------------张义---------------
|
||||||
|
|
||||||
|
#-------------薄鑫---------------
|
||||||
|
|
||||||
|
#-------------张昕浩---------------
|
||||||
|
app.include_router(example_router)
|
||||||
|
app.include_router(statistics_router, prefix="/statistics")
|
||||||
|
|
||||||
|
#-------------曾凯---------------
|
||||||
|
|
||||||
|
#-------------南方宇---------------
|
||||||
|
|
||||||
|
#-----------主程序----------------
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
uvicorn.run(app, host="0.0.0.0", port=23333)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
async def log_middleware(request, call_next):
|
||||||
|
start_time = time.time()
|
||||||
|
response = await call_next(request)
|
||||||
|
end_time = time.time()
|
||||||
|
cost = end_time - start_time
|
||||||
|
print(f'{request.method} {request.url.path} cost={cost}')
|
||||||
|
return response
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
from sqlalchemy import * # 导入sqlalchemy模块下所有的类,以便下面创建班级表模型和声明表的字段
|
||||||
|
from datetime import datetime # 导入datetime模块下的datetime类
|
||||||
|
from core.database import Base # 从core软件包下的database模块导入Base
|
||||||
|
|
||||||
|
class Classes( Base ): # 在python里的名字
|
||||||
|
__tablename__ = 'classes' # 在数据库中表的名字
|
||||||
|
#————创建班级"主键"的字段名————
|
||||||
|
id = Column( Integer # 声明字段的数据类型是"整数"
|
||||||
|
, primary_key = True # 声明是"主键"
|
||||||
|
, autoincrement = True # 声明是"自增主键"
|
||||||
|
, nullable = False # 声明是"非空"
|
||||||
|
)
|
||||||
|
# ————创建班级"编号"的字段名————
|
||||||
|
class_no = Column( String(50) # 声明字段的数据类型是"字符串,且最长为50个字符"
|
||||||
|
, unique = True # 声明是"唯一约束"
|
||||||
|
, nullable = False # 声明是"非空"
|
||||||
|
)
|
||||||
|
# ————创建"班级名称"的字段名————
|
||||||
|
class_name = Column( String(100) # 声明字段的数据类型是"字符串,且最长为100个字符"
|
||||||
|
, nullable = False # 声明是"非空"
|
||||||
|
)
|
||||||
|
# ————创建班级"开课时间"的字段名————
|
||||||
|
start_date = Column( DATE # 声明是字段数据类型是日期
|
||||||
|
, nullable = True # 声明是'可为空'
|
||||||
|
)
|
||||||
|
# ————创建班级"结课时间"的字段名————
|
||||||
|
end_date = Column( DATE # 声明是字段数据类型是'日期'
|
||||||
|
, nullable = True # 声明是"可为空"
|
||||||
|
)
|
||||||
|
# ————创建班级"创建时间"的字段名————
|
||||||
|
created_at = Column( DATETIME # 声明是字段数据类型是"日期时间"
|
||||||
|
, default=datetime.now # 声明是创建的默认值就是"当前时间"
|
||||||
|
, nullable = False # 声明是"非空"
|
||||||
|
)
|
||||||
|
# ————创建班级"更新时间"的字段名————
|
||||||
|
update_at = Column( DATETIME # 声明是字段数据类型是"日期时间"
|
||||||
|
, default=datetime.now #声明是第一次更新的时间就是第一次创建的时间一致
|
||||||
|
, onupdate=datetime.now # 声明"最后修改的时间"
|
||||||
|
, nullable = False # 声明是"非空"
|
||||||
|
)
|
||||||
|
# ————创建班级"备注信息"的字段名————
|
||||||
|
remark = Column( String(100) # 声明是字段数据类型是"字符串"
|
||||||
|
, nullable = True # 声明是"可以为空"
|
||||||
|
)
|
||||||
|
# ————创建班级"逻辑删除"的字段名————
|
||||||
|
is_deleted = Column( INTEGER # 声明是字段数据类型是"数字"
|
||||||
|
, default = 0 # 声明默认值是"0,未删除"
|
||||||
|
, nullable = False # 声明是"非空"
|
||||||
|
)
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
from sqlalchemy import (Column, Integer, String, Text,
|
||||||
|
BigInteger,ForeignKey,VARCHAR,DateTime
|
||||||
|
)
|
||||||
|
from sqlalchemy.dialects.mssql import TINYINT
|
||||||
|
|
||||||
|
from core.database import Base
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
#班级老师关系表 class_teachers_info_detail 中间表 ORM 模型完整定义
|
||||||
|
#字段包括id,class_id,teacher_id,role,created_at,updated_at,is_deleted
|
||||||
|
class ClassTeachers(Base):
|
||||||
|
__tablename__ = "class_teachers_info_detail"
|
||||||
|
id = Column(
|
||||||
|
BigInteger
|
||||||
|
,primary_key=True
|
||||||
|
,autoincrement=True
|
||||||
|
,comment='关系')
|
||||||
|
class_id = Column(
|
||||||
|
BigInteger
|
||||||
|
,ForeignKey('class_id')
|
||||||
|
,nullable=False
|
||||||
|
,comment='关联 class_id'
|
||||||
|
)
|
||||||
|
teacher_id = Column(
|
||||||
|
BigInteger
|
||||||
|
,ForeignKey('teacher_id')
|
||||||
|
,nullable=False
|
||||||
|
,comment='关联 teacher_id'
|
||||||
|
)
|
||||||
|
role = Column(
|
||||||
|
VARCHAR(30)
|
||||||
|
,nullable=False
|
||||||
|
,comment='老师在班级中的角色:head_teacher班主任 / lecturer授课老师 / assistant助教'
|
||||||
|
)
|
||||||
|
created_at = Column(
|
||||||
|
DateTime
|
||||||
|
,nullable=False
|
||||||
|
,default=datetime.now()
|
||||||
|
,comment='创建时间'
|
||||||
|
)
|
||||||
|
updated_at = Column(
|
||||||
|
DateTime
|
||||||
|
,nullable=False
|
||||||
|
,default=datetime.now()
|
||||||
|
,comment='更新时间'
|
||||||
|
)
|
||||||
|
is_deleted = Column(
|
||||||
|
TINYINT
|
||||||
|
,nullable=False
|
||||||
|
,default=0
|
||||||
|
,comment='逻辑删除'
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
from sqlalchemy import *
|
||||||
|
from datetime import datetime
|
||||||
|
from core.database import Base
|
||||||
|
class Consultant(Base):
|
||||||
|
__tablename__ = "consultants"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, autoincrement=True, comment="主键")
|
||||||
|
consultant_no = Column(String(50), unique=True, nullable=False, comment="顾问编号")
|
||||||
|
consultant_name = Column(String(50), nullable=False, comment="顾问姓名")
|
||||||
|
phone = Column(String(11), nullable=True, comment="联系电话")
|
||||||
|
email = Column(String(100), nullable=True, comment="邮箱")
|
||||||
|
remark = Column(String(255), nullable=True, comment="备注")
|
||||||
|
|
||||||
|
created_at = Column(DateTime, default=datetime.now, nullable=False, comment="创建时间")
|
||||||
|
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now, nullable=False, comment="更新时间")
|
||||||
|
is_deleted = Column(Integer, default=0, nullable=False, comment="逻辑删除:0正常,1删除")
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
from sqlalchemy import *
|
||||||
|
from sqlalchemy.orm import declarative_base,sessionmaker
|
||||||
|
from datetime import datetime
|
||||||
|
from core.database import Base, engine
|
||||||
|
|
||||||
|
# 为了符合三范式,就业表只保存 student_id,不保存学生姓名和班级名称。查询返回时通过关联 students 和 classes 带出学生姓名、班级名称。
|
||||||
|
|
||||||
|
class Employment(Base):
|
||||||
|
__tablename__ = "employments" # 实际数据库的表名字
|
||||||
|
id = Column(BigInteger, primary_key=True # 主键
|
||||||
|
, autoincrement=True # 声明是自增主键
|
||||||
|
,comment="就业信息主键id")
|
||||||
|
student_id = Column(BigInteger, ForeignKey("students.id") # 外键 -> students.id
|
||||||
|
, nullable=False # 不允许为null
|
||||||
|
,comment="关联学生id")
|
||||||
|
employment_status = Column(String(50)
|
||||||
|
, default="not_started"
|
||||||
|
,comment="就业状态:not_started/job_hunting/offered/employed")
|
||||||
|
employment_open_date = Column(Date
|
||||||
|
,comment="就业开放时间")
|
||||||
|
offer_date = Column(Date
|
||||||
|
,comment="offer下发时间")
|
||||||
|
company_name = Column(String(100)
|
||||||
|
, comment="就业公司名称")
|
||||||
|
salary = Column(DECIMAL(10, 2) # 高精度浮点数薪资,最多 10 位数字,小数占 2 位
|
||||||
|
, comment="就业薪资")
|
||||||
|
remark = Column(String(255)
|
||||||
|
,default=None
|
||||||
|
, comment="备注信息")
|
||||||
|
created_at = Column(DateTime
|
||||||
|
, default=datetime.now
|
||||||
|
, comment="创建时间")
|
||||||
|
updated_at = Column(DateTime
|
||||||
|
, default=datetime.now
|
||||||
|
, onupdate=datetime.now
|
||||||
|
,comment="更新时间")
|
||||||
|
is_deleted = Column(SmallInteger
|
||||||
|
,default=0
|
||||||
|
,comment="逻辑删除:0正常,1删除")
|
||||||
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
from sqlalchemy import *
|
||||||
|
from core.database import Base
|
||||||
|
from datetime import datetime,date
|
||||||
|
class Score(Base):
|
||||||
|
__tablename__ = "score_info_detail"
|
||||||
|
id = Column(Integer
|
||||||
|
, primary_key=True
|
||||||
|
,autoincrement=True
|
||||||
|
,comment="成绩表序号,自增主键"
|
||||||
|
)
|
||||||
|
student_id = Column(Integer
|
||||||
|
,ForeignKey("student.id")
|
||||||
|
,nullable=False
|
||||||
|
,comment="学生学号"
|
||||||
|
)
|
||||||
|
score = Column(DECIMAL(4,1)
|
||||||
|
,CheckConstraint("score between 0 and 100")
|
||||||
|
)
|
||||||
|
exam_seq= Column(Integer
|
||||||
|
, nullable=False
|
||||||
|
,comment="考试序次")
|
||||||
|
__table_args__ = (
|
||||||
|
UniqueConstraint("student_id"
|
||||||
|
, "exam_seq"
|
||||||
|
, name="uk_student_exam_seq"),
|
||||||
|
)#学生id和学生姓名应为联合唯一,即一个学生一次考试只能有一个分数
|
||||||
|
exam_date=Column(Date
|
||||||
|
,default=date.today
|
||||||
|
,comment="考试日期"
|
||||||
|
)
|
||||||
|
created_at=Column(DateTime
|
||||||
|
,default=datetime.now
|
||||||
|
,comment="创建时间"
|
||||||
|
)
|
||||||
|
updated_at=Column(DateTime
|
||||||
|
,default=datetime.now
|
||||||
|
,onupdate=datetime.now
|
||||||
|
,comment="更新时间"
|
||||||
|
)
|
||||||
|
remark=Column(String(225)
|
||||||
|
,comment="备注说明"
|
||||||
|
)
|
||||||
|
is_deleted=Column(Integer
|
||||||
|
,default=0
|
||||||
|
,comment="逻辑删除标记:未删除0,已删除1"
|
||||||
|
)
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
from core.database import Base
|
||||||
|
from sqlalchemy import *
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class Student(Base):
|
||||||
|
__tablename__ = 'student_info_detail'
|
||||||
|
id = Column(Integer
|
||||||
|
, primary_key=True
|
||||||
|
, autoincrement=True
|
||||||
|
, comment = '学生编号,自增主键'
|
||||||
|
)
|
||||||
|
student_no = Column(VARCHAR(50)
|
||||||
|
, unique = True)
|
||||||
|
student_name = Column(VARCHAR(50))
|
||||||
|
class_id = Column(Integer
|
||||||
|
,foreign_key = 'class_info_detail.id'
|
||||||
|
)#外键约束 班级表的主键id,存在这个班级,学生表才可以输入
|
||||||
|
consultant_id = Column(Integer
|
||||||
|
,nullable = True
|
||||||
|
,foreign_key = 'consultant_info_detail.id'
|
||||||
|
)#外键约束 顾问表的主键id,存在这个顾问,才可以写入,允许为空
|
||||||
|
native_place = Column(VARCHAR(100)
|
||||||
|
,nullable = True)
|
||||||
|
graduation_school = Column(VARCHAR(100)
|
||||||
|
,nullable = True)
|
||||||
|
major = Column(VARCHAR(100)
|
||||||
|
,nullable = True)
|
||||||
|
enrollment_date = Column(Date
|
||||||
|
,nullable = False)#入学时间必填
|
||||||
|
graduation_date = Column(Date,
|
||||||
|
nullable = True)#毕业时间可以为空
|
||||||
|
education = Column(VARCHAR(50)
|
||||||
|
,nullable = True)#学历可以为空
|
||||||
|
age = Column(Integer
|
||||||
|
,nullable = False)
|
||||||
|
gender = Column(VARCHAR(10)
|
||||||
|
,nullable = False)
|
||||||
|
create_at = Column(DATETIME
|
||||||
|
,default = datetime.now)
|
||||||
|
update_at = Column(DATETIME
|
||||||
|
,default = datetime.now
|
||||||
|
,onupdate = datetime.now)
|
||||||
|
is_deleted = Column(Integer
|
||||||
|
,default = 0)#逻辑删除,默认为0,为1则表示已删除
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
from sqlalchemy import (Column, Integer,VARCHAR,DateTime
|
||||||
|
)
|
||||||
|
from sqlalchemy.dialects.mssql import TINYINT
|
||||||
|
|
||||||
|
from core.database import Base
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
# teachers 老师表 ORM 模型
|
||||||
|
#字段包括id,teacher_no,teacher_name,phone,email,remark,created_at,updated_at,is_deleted
|
||||||
|
class Teacher(Base):
|
||||||
|
__tablename__ = 'teachers_info_detail'
|
||||||
|
id = Column(
|
||||||
|
Integer
|
||||||
|
, primary_key=True
|
||||||
|
,autoincrement=True
|
||||||
|
,comment='老师主键')
|
||||||
|
teacher_no = Column(
|
||||||
|
VARCHAR(50)
|
||||||
|
,nullable=False
|
||||||
|
,unique=True
|
||||||
|
,comment='老师编号'
|
||||||
|
)
|
||||||
|
teacher_name = Column(
|
||||||
|
VARCHAR(50)
|
||||||
|
,nullable=False
|
||||||
|
,comment='老师名字'
|
||||||
|
)
|
||||||
|
phone = Column(
|
||||||
|
VARCHAR(20)
|
||||||
|
,nullable=True
|
||||||
|
,comment='老师电话'
|
||||||
|
)
|
||||||
|
email = Column(
|
||||||
|
VARCHAR(100)
|
||||||
|
,nullable=True
|
||||||
|
,comment='邮箱'
|
||||||
|
)
|
||||||
|
remark = Column(
|
||||||
|
VARCHAR(2550)
|
||||||
|
,nullable=True
|
||||||
|
,comment='备注'
|
||||||
|
)
|
||||||
|
created_at = Column(
|
||||||
|
DateTime
|
||||||
|
,nullable=False
|
||||||
|
,default=datetime.now
|
||||||
|
,comment='创建时间'
|
||||||
|
)
|
||||||
|
updated_at = Column(
|
||||||
|
DateTime
|
||||||
|
,nullable=False
|
||||||
|
,default=datetime.now
|
||||||
|
,comment='更新时间'
|
||||||
|
)
|
||||||
|
is_deleted = Column(
|
||||||
|
TINYINT
|
||||||
|
,nullable=False
|
||||||
|
,default=0
|
||||||
|
,comment='逻辑删除'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fastapi==0.128.0
|
||||||
|
uvicorn==0.40.0
|
||||||
|
SQLAlchemy==2.0.49
|
||||||
|
PyMySQL==1.1.2
|
||||||
|
pydantic==2.13.3
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
from pydantic import BaseModel # 导入pydantic模块下的BaseModel类
|
||||||
|
from datetime import datetime,date # 导入datetime模块下的datetime,date类
|
||||||
|
|
||||||
|
|
||||||
|
# ————定义"创建班级"的"请求体"模型————
|
||||||
|
class ClassCreate( BaseModel ):
|
||||||
|
class_no: str
|
||||||
|
class_name: str
|
||||||
|
|
||||||
|
# ————定义"更新班级"的"请求体"模型————
|
||||||
|
class ClassUpdate( BaseModel ):
|
||||||
|
class_no: str|None = None
|
||||||
|
class_name: str|None = None
|
||||||
|
start_date : date|None = None
|
||||||
|
end_date : date|None = None
|
||||||
|
created_at : datetime|None = None
|
||||||
|
update_at : datetime|None = None
|
||||||
|
|
||||||
|
# ————定义"班级"的"响应体"模型————
|
||||||
|
class ClassResponse( BaseModel ):
|
||||||
|
code:int = 200
|
||||||
|
detail:str = '执行成功'
|
||||||
|
total:int = 0
|
||||||
|
data:str|dict|list|tuple
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
'''
|
||||||
|
两种情况:
|
||||||
|
1.响应成功,响应体设置为SuccessResponse。
|
||||||
|
2.响应失败,需要主动调用HTTPExpection报错,不然会产生响应码200,响应失败的问题。
|
||||||
|
'''
|
||||||
|
from pydantic import BaseModel,Field
|
||||||
|
from typing import Any
|
||||||
|
class SuccessResponse(BaseModel):
|
||||||
|
status_code:int=Field(default=200, ge= 200, lt = 300)
|
||||||
|
msg: Any=Field(default='OK')
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
class NoExist(Exception):
|
||||||
|
def __init__(self,value):
|
||||||
|
self.value = value
|
||||||
|
pass
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
class StudentCreate(BaseModel):
|
||||||
|
student_no: str|None = None
|
||||||
|
student_name: str
|
||||||
|
class_id: int
|
||||||
|
consultant_id: int | None = None
|
||||||
|
native_place: str | None = None
|
||||||
|
graduate_school: str | None = None
|
||||||
|
major: str | None = None
|
||||||
|
enrollment_date: date
|
||||||
|
graduation_date: date | None = None
|
||||||
|
education: str | None = None
|
||||||
|
age: int
|
||||||
|
gender: str
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import Optional
|
||||||
|
from datetime import datetime
|
||||||
|
#===============老师表===================
|
||||||
|
#===============请求体模型================
|
||||||
|
class TeacherCreate(BaseModel):
|
||||||
|
teacher_no: Optional[str] = None
|
||||||
|
teacher_name: Optional[str] = None
|
||||||
|
email: Optional[str] = None
|
||||||
|
phone: Optional[str] = None
|
||||||
|
remark: Optional[str] = None
|
||||||
|
|
||||||
|
class TeacherUpdate(BaseModel):
|
||||||
|
teacher_no: Optional[str] = None
|
||||||
|
teacher_name: Optional[str] = None
|
||||||
|
email: Optional[str] = None
|
||||||
|
phone: Optional[str] = None
|
||||||
|
remark: Optional[str] = None
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
'''
|
||||||
|
1. 参数说明:
|
||||||
|
field_name:业务编号字段名,例如 student_no
|
||||||
|
prefix:业务编号前缀,例如 STU
|
||||||
|
db_object:已实例化的 ORM 对象,例如 stu
|
||||||
|
db:当前接口中的数据库 Session
|
||||||
|
|
||||||
|
2. ORM 主键统一命名为 id。
|
||||||
|
业务编号字段按文档命名,例如 student_no、teacher_no、class_no。
|
||||||
|
|
||||||
|
3. 必须先执行 db.add(db_object),再调用 generate_no()。
|
||||||
|
|
||||||
|
4. 主键id一定要设置成自增。
|
||||||
|
|
||||||
|
|
||||||
|
dao模块示例代码:
|
||||||
|
def add_student(
|
||||||
|
result: CreateStudent,
|
||||||
|
db: Session
|
||||||
|
):
|
||||||
|
stu = Student(**result.model_dump())
|
||||||
|
|
||||||
|
db.add(stu)
|
||||||
|
|
||||||
|
generate_no("student_no", "STU", stu, db)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return stu
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def generate_no(field_name: str, prefix: str, db_object, db: Session):
|
||||||
|
if getattr(db_object, field_name):
|
||||||
|
return
|
||||||
|
|
||||||
|
db.flush()
|
||||||
|
record_no = f"{prefix}{db_object.id:04d}"
|
||||||
|
setattr(db_object, field_name, record_no)
|
||||||
Reference in New Issue
Block a user