from pydantic import BaseModel, Field, model_validator, field_validator, ConfigDict from datetime import date 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 对象转换