第一版_完整

This commit is contained in:
jianqi
2026-09-14 11:34:08 +08:00
parent e8646724b4
commit 414de4bad8
26 changed files with 1422 additions and 307 deletions
+122
View File
@@ -0,0 +1,122 @@
# scheme/employ.py
from datetime import date
from decimal import Decimal
from typing import List
from pydantic import Field, field_validator, model_validator, ValidationError, BaseModel
from database import Base
# ---------- -------------------------------请求模型 ------------------------------------------------
class YearMonthDay(BaseModel):
year : int | None = Field(None,description="年份")
month: int | None = Field(None, le=12,ge=1 ,description="月份")
day: int | None = Field(None,ge=1 ,description="日期")
@model_validator(mode='after')
def check_year_month_day(self):
having_none = (self.year and self.month and self.day)
all_none= (not self.year and not self.month and not self.day)
all_has = (self.year and self.month and self.day and len(str(self.year))==4)
# if not having_none:
# raise ValueError("年月日必须全部填写或者全部为空")
if all_none:
return None
if all_has:
if self.month==2:
if (self.year % 4 == 0 and self.year % 100 != 0) or (self.year % 400 == 0):
if self.day>29:
raise ValueError("闰年2月最多29天")
return self
else:
if self.day > 28:
raise ValueError("平年2月最多28天")
return self
elif self.month in (1,3,5,7,8,10,12):
if self.day > 31:
raise ValueError("大月最多31天")
return self
else:
if self.day > 30:
raise ValueError("小月最多30天")
return self
raise ValueError("年月日必须全部填写或者全部为空,且年份必须为4位数")
# 定义 记录学生就业状态 请求体模型
class EmployStatusCreate(BaseModel):
"""
记录学生就业状态接口,需要传入的请求体
"""
stu_id: str = Field(..., description="学号,非空唯一")
emp_open_time: YearMonthDay | None = Field(None, description="就业开放时间,可更改学生就业状态")
send_offer_time: YearMonthDay | None = Field(None, description="offer下发时间,可更改学生就业状态")
emp_company: str | None = Field(None, description="就业公司名称")
salary: Decimal | None = Field(None, decimal_places=2,description="就业薪资,默认为空") # 薪资精确到2小数
@model_validator(mode='after')
def check_offer_and_open_time(self):
"""
自定义校验,就业开放时间必须 早于等于 offer下发时间,否则抛出422参数异常状态码;
并且返回 就业状态记录 对象 自己
:return:
"""
s, e = self.send_offer_time, self.emp_open_time
if s and e:
send_offer_time = date(s.year,s.month,s.day)
emp_open_time = date(e.year,e.month,e.day)
if send_offer_time < emp_open_time: # offer下发时间不能早于就业开放时间
raise ValueError("offer下发时间不能早于就业开放时间")
return self
if not e:
if s and self.emp_company and self.salary: # 就业开放时间为null,offer下发时间、就业公司、薪水不能填写
raise ValueError("学生在读,无法添加就业信息")
return self
else:
if not s:
if self.emp_company and self.salary: # offer下发时间为null,就业公司、薪水不能填写
raise ValueError("学生进入就业中,无法添加已就业信息")
return self
if not self.emp_company and not self.salary:
raise ValueError("学生已就业,必须填写已就业信息") # 学生已就业,就业公司、薪水必须填写
return self
# 定义 查询学生就业状态 请求体模型
class EmployStatusQuery(BaseModel):
"""
请求体传入学生编号(可选)、就业公司(可选)、薪资范围(可选)
可多条件查询 学生就业信息
"""
stu_id: str | None = Field(None, description="根据学生编号查询")
emp_company: str | None = Field(None, description="根据就业公司名称查询")
min_salary: Decimal | None = Field(None, decimal_places=2,description="查询的就业薪资范围最小值") # 薪资精确到2小数
max_salary: Decimal | None = Field(None, decimal_places=2, description="查询的就业薪资范围最大值") # 薪资精确到2小数
skip:int = Field(1, description="页码")
limit: int = Field(10, description="每页条数")
# 定义 删除学生就业状态 请求体模型
class EmployStatusDelete(BaseModel):
"""
请求体传入学生编号(可选)、就业公司(可选)、薪资范围(可选)
可多条件查询 学生就业信息
"""
stu_id: str = Field(..., description="根据学生编号查询")
# ------------------------------------------ 响应模型 ------------------------------------------------
class EmployStatusResponse(BaseModel):
stu_id: str
emp_open_time: YearMonthDay | None
send_offer_time: YearMonthDay | None
emp_company: str | None
salary: Decimal | None = Field(None, decimal_places=2,description="就业薪资,默认为空") # 薪资精确到2小数
class EmployDateResponse(BaseModel):
stu_id: str
emp_open_time: date | None
send_offer_time: date | None
emp_company: str | None
salary: Decimal | None = Field(None, decimal_places=2,description="就业薪资,默认为空") # 薪资精确到2小数
class EmployQueryResponse(BaseModel):
employ_info : List[EmployDateResponse] | None
total:int
-22
View File
@@ -1,22 +0,0 @@
# scheme/statistics_scheme.py
from pydantic import BaseModel, Field, EmailStr
from datetime import datetime
from typing import Optional
# ---------- 请求模型 ----------
# class UserCreate(BaseModel):
# username: str = Field(..., min_length=3, max_length=50)
# email: EmailStr
# full_name: Optional[str] = Field(None, max_length=100)
#
# class UserUpdate(BaseModel):
# username: Optional[str] = Field(None, min_length=3, max_length=50)
# email: Optional[EmailStr] = None
# full_name: Optional[str] = Field(None, max_length=100)
# ---------- 响应模型 ----------
# 多维度班级统计
class StatsResponse(BaseModel):
total_count: int
man_count: int
female_count: int
+80
View File
@@ -0,0 +1,80 @@
from pydantic import BaseModel, Field, model_validator, field_validator, ConfigDict
from datetime import date, datetime
from typing import Optional
#id用cls_id来拼接生成,不用请求体过滤
#------------新增请求体-------------
class StudentCreate(BaseModel):
cls_id: int | str = Field(..., description="班级ID,6位数字")
name: str = Field(..., min_length=1, max_length=20, description="姓名")
gender: str = Field(..., min_length=1, max_length=1, description="性别")
age: int = Field(..., ge=1, le=100, description="年龄")
hometown: Optional[str] = Field(None, min_length=3, max_length=50, description="籍贯")
grad_school: str = Field(..., min_length=1, max_length=50, description="毕业院校")
major: str = Field(..., min_length=1, max_length=50, description="专业名称")
education: str = Field(..., min_length=1, max_length=20, description="学历")
enr_date: date = Field(..., description="入学日期")
grad_date: date = Field(..., description="毕业日期")
advisor_id: str = Field(..., min_length=1, max_length=15, description="顾问编号")
#校验入学时间必须比毕业时间小
@model_validator(mode='after')
def check_dates(self):
if self.grad_date <= self.enr_date:
raise ValueError("毕业日期必须晚于入学日期")
return self
# 校验传入的6位数是不是都是数字/都转化为字符串判断
@field_validator("cls_id", mode="before")
def convert_str(cls, v):
# 不管前端传数字还是字符串,统一转字符串
v = str(v)
if len(v) != 6 or not v.isdigit():
raise ValueError("班级ID必须是6位纯数字")
return v
#------------修改请求体-------------
class StudentUpdate(BaseModel):
cls_id: Optional[int|str] = Field(None, description="班级ID,6位数字")
name: Optional[str] = Field(None, min_length=1, max_length=20, description="姓名")
gender: Optional[str] = Field(None, min_length=1, max_length=1, description="性别")
age: Optional[int] = Field(None, ge=1, le=100, description="年龄")
hometown: Optional[str] = Field(None, min_length=3, max_length=50, description="籍贯")
grad_school: Optional[str] = Field(None, min_length=1, max_length=50, description="毕业院校")
major: Optional[str] = Field(None, min_length=1, max_length=50, description="专业名称")
education: Optional[str] = Field(None, min_length=1, max_length=20, description="学历")
enr_date: Optional[date]= Field(None, description="入学日期")
grad_date: Optional[date]= Field(None, description="毕业日期")
advisor_id: Optional[str] = Field(None, min_length=1, max_length=15, description="顾问编号")
@field_validator("cls_id", mode="before")
def convert_str(cls, v):
# 更新:不传cls_id(v=None)直接返回,跳过校验
if v is None:
return v
v = str(v)
if len(v) != 6 or not v.isdigit():
raise ValueError("班级ID必须是6位纯数字")
return v
@model_validator(mode='after')
def check_dates(self):
# 只在两个日期【都传了,不为None】的时候,才校验大小,传单个时在api层校验
if self.grad_date is not None and self.enr_date is not None:
if self.grad_date <= self.enr_date:
raise ValueError("毕业日期必须晚于入学日期")
return self
#--------------响应体模型--------------
class StudentResponse(BaseModel):
id: str
cls_id: str
name: str
gender: str
age: int
hometown: Optional[str]
grad_school: Optional[str]
major: Optional[str]
education: Optional[str]
enr_date: Optional[date]
grad_date: Optional[date]
advisor_id: Optional[str]
state: Optional[str]
model_config = ConfigDict(from_attributes=True) # 支持 ORM 对象转换
+28
View File
@@ -0,0 +1,28 @@
# scheme/stu_score_scheme.py
import decimal
from pydantic import BaseModel, Field
# from datetime import datetime
# from typing import Optional
# ---------- 请求模型 ----------
# ---------- 响应模型 ----------
class StuScoreResponse(BaseModel):
stu_id: str
exam_attempt: int
exam_score: decimal.Decimal = Field(max_digits=5, decimal_places=2)
score_level:str
class StuScoreCreateResponse(BaseModel):
stu_id: str
exam_attempt: int
exam_score: decimal.Decimal = Field(max_digits=5, decimal_places=2)
score_level: str
warnings:str|None= None
class Config:
from_attributes = True # 支持 ORM 对象转换
+46
View File
@@ -0,0 +1,46 @@
#老师表请求体模型
from http.client import HTTPException
from typing import Optional
from fastapi.openapi.utils import status_code_ranges
from pydantic import Field, BaseModel, field_validator
from database import Base # Base 在 database.py 中
#添加教师信息请求体
class TeacherAdd(BaseModel):
name : str = Field(..., max_length=50,description="姓名")
phone : str = Field(..., description="手机号")
type : str = Field(..., max_length=50, description="教师类型")
# 校验器 输入手机号必须为11位
@field_validator("phone")
@classmethod #类方法
def phone_length(cls, v:str):
if len(v) != 11:
raise ValueError('手机号必须为11位')
return v
class TeacherUpdate(BaseModel):
name: Optional[str] = Field(None,max_length=50, description="姓名")
phone: Optional[str] = Field(None,description="手机号")
type: Optional[str] = Field(None,max_length=50, description="教师类型")
#校验器 输入手机号必须为11位
@field_validator("phone")
@classmethod #类方法
def phone_length(cls, v: Optional[str]):
if v is not None and len(v) != 11:
raise ValueError('手机号必须为11位')
return v
#教师响应体模型
class TeacherResponse(BaseModel):
id: str
name: str
phone: str
type: str
-27
View File
@@ -1,27 +0,0 @@
# scheme/users.py
from pydantic import BaseModel, Field, EmailStr
from datetime import datetime
from typing import Optional
# ---------- 请求模型 ----------
class UserCreate(BaseModel):
username: str = Field(..., min_length=3, max_length=50)
email: EmailStr
full_name: Optional[str] = Field(None, max_length=100)
class UserUpdate(BaseModel):
username: Optional[str] = Field(None, min_length=3, max_length=50)
email: Optional[EmailStr] = None
full_name: Optional[str] = Field(None, max_length=100)
# ---------- 响应模型 ----------
class UserResponse(BaseModel):
id: int
username: str
email: str
full_name: Optional[str]
created_at: datetime
updated_at: Optional[datetime]
class Config:
from_attributes = True # 支持 ORM 对象转换