diff --git a/schema/face_schema.py b/schema/face_schema.py index 5bb5a80..99b1a59 100644 --- a/schema/face_schema.py +++ b/schema/face_schema.py @@ -6,28 +6,25 @@ from pydantic import BaseModel, Field # 请求模型(前端传参校验) # ------------------------------ class FaceCreateRequest(BaseModel): - """创建人脸记录请求模型""" - id: int = Field(..., description="主键ID") - name: str = Field(None, max_length=255, description="名称") - eigenvalue: str = Field(None, max_length=255, description="特征") + """创建人脸记录请求模型(无需ID,由数据库自增)""" + name: str = Field(None, max_length=255, description="名称(可选,最长255字符)") class FaceUpdateRequest(BaseModel): - """更新人脸记录请求模型""" + """更新人脸记录请求模型(不变)""" name: str = Field(None, max_length=255, description="名称") - eigenvalue: str = Field(None, max_length=255, description="特征") + eigenvalue: str = Field(None, max_length=255, description="特征(文件处理后可更新)") # ------------------------------ # 响应模型(后端返回数据) # ------------------------------ class FaceResponse(BaseModel): - """人脸记录响应模型""" - id: int = Field(..., description="主键ID") + """人脸记录响应模型(仍包含ID,由数据库生成后返回)""" + id: int = Field(..., description="主键ID(数据库自增)") name: str = Field(None, description="名称") - eigenvalue: str = Field(None, description="特征") + eigenvalue: str = Field(None, description="特征(暂为None)") created_at: datetime = Field(..., description="记录创建时间") updated_at: datetime = Field(..., description="记录更新时间") - # 支持从数据库查询结果转换 - model_config = {"from_attributes": True} + model_config = {"from_attributes": True} \ No newline at end of file diff --git a/service/face_service.py b/service/face_service.py index 7d767d7..8b86042 100644 --- a/service/face_service.py +++ b/service/face_service.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends, HTTPException +from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form from mysql.connector import Error as MySQLError from ds.db import db @@ -7,7 +7,6 @@ from schema.response_schema import APIResponse from middle.auth_middleware import get_current_user from schema.user_schema import UserResponse -# 创建人脸接口路由(前缀 /faces、标签用于 Swagger 分类) router = APIRouter( prefix="/faces", tags=["人脸管理"] @@ -15,50 +14,52 @@ router = APIRouter( # ------------------------------ -# 1. 创建人脸记录 +# 1. 创建人脸记录(核心修正:ID 数据库自增,前端无需传) # ------------------------------ -@router.post("", response_model=APIResponse, summary="创建人脸记录") +@router.post("", response_model=APIResponse, summary="创建人脸记录(传名称+文件,ID自增)") async def create_face( - face: FaceCreateRequest + # 前端仅需传:name(可选,Form格式)、file(必传,文件) + name: str = Form(None, max_length=255, description="名称(可选)"), + file: UploadFile = File(..., description="人脸文件(必传,暂不处理内容)") ): """ 创建人脸记录: - 需登录认证 - - 插入新的人脸记录到数据库 - - 返回创建成功信息 + - 前端传参:multipart/form-data 表单(name 可选,file 必传) + - ID 由数据库自动生成,无需前端传入 + - 暂不处理文件内容,eigenvalue 设为 None """ conn = None cursor = None try: + # 1. 用模型校验 name(仅校验长度,无需ID) + face_create = FaceCreateRequest(name=name) + conn = db.get_connection() cursor = conn.cursor(dictionary=True) - # 1. 检查ID是否已存在 - check_query = "SELECT id FROM face WHERE id = %s" - cursor.execute(check_query, (face.id,)) - existing_face = cursor.fetchone() - if existing_face: - raise HTTPException( - status_code=400, - detail=f"ID为 {face.id} 的人脸记录已存在" - ) + # 把文件转为二进制数组 + file_content = await file.read() - # 2. 插入新人脸记录到数据库 + # 调用人脸识别得到特征值 + + + # 2. 插入数据库:无需传 ID(自增),只传 name 和 eigenvalue(None) insert_query = """ - INSERT INTO face (id, name, eigenvalue) - VALUES (%s, %s, %s) + INSERT INTO face (name, eigenvalue) + VALUES (%s, %s) """ - cursor.execute(insert_query, (face.id, face.name, face.eigenvalue)) + cursor.execute(insert_query, (face_create.name, None)) conn.commit() - # 3. 查询刚创建的记录并返回 - select_query = "SELECT * FROM face WHERE id = %s" - cursor.execute(select_query, (face.id,)) + # 3. 获取数据库自动生成的 ID(关键:用 LAST_INSERT_ID() 查刚插入的记录) + select_new_query = "SELECT * FROM face WHERE id = LAST_INSERT_ID()" + cursor.execute(select_new_query) created_face = cursor.fetchone() return APIResponse( - code=201, # 201 表示资源创建成功 - message="人脸记录创建成功", + code=201, + message=f"人脸记录创建成功(ID:{created_face['id']},文件名:{file.filename})", data=FaceResponse(**created_face) ) except MySQLError as e: @@ -66,23 +67,18 @@ async def create_face( conn.rollback() raise Exception(f"创建人脸记录失败:{str(e)}") from e finally: + await file.close() # 关闭文件流 db.close_connection(conn, cursor) # ------------------------------ -# 2. 获取单个人脸记录 +# 2. 获取单个人脸记录(不变,用自增ID查询) # ------------------------------ @router.get("/{face_id}", response_model=APIResponse, summary="获取单个人脸记录") async def get_face( - face_id: int, - current_user: UserResponse = Depends(get_current_user) # 需登录认证 + face_id: int, # 这里的 ID 是数据库自增的,前端从创建响应中获取 + current_user: UserResponse = Depends(get_current_user) ): - """ - 获取单个人脸记录: - - 需登录认证 - - 根据ID查询人脸记录 - - 返回查询到的人脸信息 - """ conn = None cursor = None try: @@ -110,25 +106,21 @@ async def get_face( db.close_connection(conn, cursor) +# 后续 3.获取所有、4.更新、5.删除 接口(不变,仅用数据库自增的 ID 操作,无需修改) # ------------------------------ -# 3. 获取所有人脸记录 +# 3. 获取所有人脸记录(不变) # ------------------------------ @router.get("", response_model=APIResponse, summary="获取所有人脸记录") async def get_all_faces( + current_user: UserResponse = Depends(get_current_user) ): - """ - 获取所有人脸记录: - - 需登录认证 - - 查询所有人脸记录(不需要分页) - - 返回所有人脸信息列表 - """ conn = None cursor = None try: conn = db.get_connection() cursor = conn.cursor(dictionary=True) - query = "SELECT * FROM face ORDER BY id" + query = "SELECT * FROM face ORDER BY id" # 按自增ID排序 cursor.execute(query) faces = cursor.fetchall() @@ -144,27 +136,21 @@ async def get_all_faces( # ------------------------------ -# 4. 更新人脸记录 +# 4. 更新人脸记录(不变,用自增ID更新) # ------------------------------ @router.put("/{face_id}", response_model=APIResponse, summary="更新人脸记录") async def update_face( face_id: int, face_update: FaceUpdateRequest, - current_user: UserResponse = Depends(get_current_user) # 需登录认证 + current_user: UserResponse = Depends(get_current_user) ): - """ - 更新人脸记录: - - 需登录认证 - - 根据ID更新人脸记录信息 - - 返回更新后的人脸信息 - """ conn = None cursor = None try: conn = db.get_connection() cursor = conn.cursor(dictionary=True) - # 1. 检查记录是否存在 + # 检查记录是否存在 check_query = "SELECT id FROM face WHERE id = %s" cursor.execute(check_query, (face_id,)) existing_face = cursor.fetchone() @@ -174,35 +160,25 @@ async def update_face( detail=f"ID为 {face_id} 的人脸记录不存在" ) - # 2. 构建更新语句(只更新提供的字段) + # 构建更新语句 update_fields = [] params = [] - if face_update.name is not None: update_fields.append("name = %s") params.append(face_update.name) - if face_update.eigenvalue is not None: update_fields.append("eigenvalue = %s") params.append(face_update.eigenvalue) if not update_fields: - raise HTTPException( - status_code=400, - detail="至少需要提供一个字段进行更新" - ) + raise HTTPException(status_code=400, detail="至少需提供一个更新字段") - params.append(face_id) # WHERE条件的参数 - - update_query = f""" - UPDATE face - SET {', '.join(update_fields)}, updated_at = CURRENT_TIMESTAMP - WHERE id = %s - """ + params.append(face_id) + update_query = f"UPDATE face SET {', '.join(update_fields)}, updated_at = CURRENT_TIMESTAMP WHERE id = %s" cursor.execute(update_query, params) conn.commit() - # 3. 查询更新后的记录并返回 + # 查询更新后记录 select_query = "SELECT * FROM face WHERE id = %s" cursor.execute(select_query, (face_id,)) updated_face = cursor.fetchone() @@ -221,26 +197,19 @@ async def update_face( # ------------------------------ -# 5. 删除人脸记录 +# 5. 删除人脸记录(不变,用自增ID删除) # ------------------------------ @router.delete("/{face_id}", response_model=APIResponse, summary="删除人脸记录") async def delete_face( face_id: int, - current_user: UserResponse = Depends(get_current_user) # 需登录认证 + current_user: UserResponse = Depends(get_current_user) ): - """ - 删除人脸记录: - - 需登录认证 - - 根据ID删除人脸记录 - - 返回删除成功信息 - """ conn = None cursor = None try: conn = db.get_connection() cursor = conn.cursor(dictionary=True) - # 1. 检查记录是否存在 check_query = "SELECT id FROM face WHERE id = %s" cursor.execute(check_query, (face_id,)) existing_face = cursor.fetchone() @@ -250,7 +219,6 @@ async def delete_face( detail=f"ID为 {face_id} 的人脸记录不存在" ) - # 2. 执行删除操作 delete_query = "DELETE FROM face WHERE id = %s" cursor.execute(delete_query, (face_id,)) conn.commit()