|
@@ -6,11 +6,11 @@ from typing import Optional, Dict, Any, List
|
|
|
|
|
|
|
|
from fastapi import APIRouter, File, UploadFile, Depends, HTTPException, Form, Query
|
|
from fastapi import APIRouter, File, UploadFile, Depends, HTTPException, Form, Query
|
|
|
from fastapi.responses import JSONResponse, FileResponse
|
|
from fastapi.responses import JSONResponse, FileResponse
|
|
|
-from pydantic import BaseModel, field_validator
|
|
|
|
|
from mysql.connector.pooling import PooledMySQLConnection
|
|
from mysql.connector.pooling import PooledMySQLConnection
|
|
|
|
|
|
|
|
from app.core.config import settings
|
|
from app.core.config import settings
|
|
|
from app.core.logger import get_logger
|
|
from app.core.logger import get_logger
|
|
|
|
|
+from app.utils.scheme import ImageRecordResponse, map_row_to_model
|
|
|
from app.core.database_loader import get_db_connection
|
|
from app.core.database_loader import get_db_connection
|
|
|
|
|
|
|
|
# --- 初始化 ---
|
|
# --- 初始化 ---
|
|
@@ -21,40 +21,6 @@ router = APIRouter()
|
|
|
db_dependency = Depends(get_db_connection)
|
|
db_dependency = Depends(get_db_connection)
|
|
|
|
|
|
|
|
|
|
|
|
|
-# --- Pydantic 数据模型 ---
|
|
|
|
|
-class ImageRecordResponse(BaseModel):
|
|
|
|
|
- """用于API响应的数据模型,确保数据结构一致"""
|
|
|
|
|
- img_id: int
|
|
|
|
|
- img_name: Optional[str] = None
|
|
|
|
|
- img_path: str
|
|
|
|
|
- img_result_json: Dict[str, Any]
|
|
|
|
|
- created_at: datetime
|
|
|
|
|
-
|
|
|
|
|
- @field_validator('img_result_json', mode='before')
|
|
|
|
|
- @classmethod
|
|
|
|
|
- def parse_json_string(cls, v):
|
|
|
|
|
- """
|
|
|
|
|
- 这个验证器会在Pydantic进行类型检查之前运行 (因为 pre=True)。
|
|
|
|
|
- 它负责将从数据库取出的JSON字符串转换为Python字典。
|
|
|
|
|
- """
|
|
|
|
|
- if isinstance(v, str):
|
|
|
|
|
- try:
|
|
|
|
|
- return json.loads(v)
|
|
|
|
|
- except json.JSONDecodeError:
|
|
|
|
|
- # 如果数据库中的JSON格式错误,则抛出异常
|
|
|
|
|
- raise ValueError("Invalid JSON string in database")
|
|
|
|
|
- return v
|
|
|
|
|
- # --- FIX ENDS HERE ---
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-# --- 辅助函数 ---
|
|
|
|
|
-def map_row_to_model(row: tuple, columns: List[str]) -> ImageRecordResponse:
|
|
|
|
|
- """将数据库查询出的一行数据映射到Pydantic模型"""
|
|
|
|
|
- row_dict = dict(zip(columns, row))
|
|
|
|
|
- # 现在当 ImageRecordResponse 被调用时,上面的验证器会先生效
|
|
|
|
|
- return ImageRecordResponse(**row_dict)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
# --- API 接口实现 ---
|
|
# --- API 接口实现 ---
|
|
|
|
|
|
|
|
# 1: 存储图片和JSON数据
|
|
# 1: 存储图片和JSON数据
|
|
@@ -217,8 +183,6 @@ def get_records_by_name(img_name: str, db_conn: PooledMySQLConnection = db_depen
|
|
|
cursor.close()
|
|
cursor.close()
|
|
|
|
|
|
|
|
|
|
|
|
|
-# ... (其他接口代码保持不变) ...
|
|
|
|
|
-
|
|
|
|
|
# 5: 修改JSON数据
|
|
# 5: 修改JSON数据
|
|
|
@router.put("/update/json/{img_id}", status_code=200, summary="5. 修改指定ID记录的JSON数据")
|
|
@router.put("/update/json/{img_id}", status_code=200, summary="5. 修改指定ID记录的JSON数据")
|
|
|
def update_record_json(
|
|
def update_record_json(
|
|
@@ -231,7 +195,7 @@ def update_record_json(
|
|
|
try:
|
|
try:
|
|
|
cursor = db_conn.cursor()
|
|
cursor = db_conn.cursor()
|
|
|
new_json_str = json.dumps(new_json_data, ensure_ascii=False)
|
|
new_json_str = json.dumps(new_json_data, ensure_ascii=False)
|
|
|
- query = f"UPDATE {settings.DB_TABLE_NAME} SET img_result_json = %s WHERE img_id = %s"
|
|
|
|
|
|
|
+ query = f"UPDATE {settings.DB_TABLE_NAME} SET img_result_json_new = %s WHERE img_id = %s"
|
|
|
cursor.execute(query, (new_json_str, img_id))
|
|
cursor.execute(query, (new_json_str, img_id))
|
|
|
|
|
|
|
|
if cursor.rowcount == 0:
|
|
if cursor.rowcount == 0:
|
|
@@ -282,18 +246,26 @@ def get_image_file(img_id: int, db_conn: PooledMySQLConnection = db_dependency):
|
|
|
# 7: 获取JSON数据
|
|
# 7: 获取JSON数据
|
|
|
@router.get("/json/{img_id}", summary="7. 获取指定ID的JSON数据")
|
|
@router.get("/json/{img_id}", summary="7. 获取指定ID的JSON数据")
|
|
|
def get_record_json(img_id: int, db_conn: PooledMySQLConnection = db_dependency):
|
|
def get_record_json(img_id: int, db_conn: PooledMySQLConnection = db_dependency):
|
|
|
- """根据img_id查找记录,并仅返回其JSON数据部分。"""
|
|
|
|
|
|
|
+ """
|
|
|
|
|
+ 根据img_id查找记录,并仅返回其JSON数据部分。
|
|
|
|
|
+ 优先返回 img_result_json_new,如果为 NULL 则返回 img_result_json。
|
|
|
|
|
+ """
|
|
|
cursor = None
|
|
cursor = None
|
|
|
try:
|
|
try:
|
|
|
cursor = db_conn.cursor()
|
|
cursor = db_conn.cursor()
|
|
|
- query = f"SELECT img_result_json FROM {settings.DB_TABLE_NAME} WHERE img_id = %s"
|
|
|
|
|
|
|
+ query = (
|
|
|
|
|
+ f"SELECT IFNULL({settings.DB_TABLE_NAME}.img_result_json_new, {settings.DB_TABLE_NAME}.img_result_json) AS img_result_json "
|
|
|
|
|
+ f"FROM {settings.DB_TABLE_NAME} WHERE img_id = %s"
|
|
|
|
|
+ )
|
|
|
cursor.execute(query, (img_id,))
|
|
cursor.execute(query, (img_id,))
|
|
|
- result = cursor.fetchone()
|
|
|
|
|
|
|
+ result = cursor.fetchone() # result will be a tuple like ('{"key": "value"}',)
|
|
|
if not result:
|
|
if not result:
|
|
|
raise HTTPException(status_code=404, detail=f"ID为 {img_id} 的记录未找到。")
|
|
raise HTTPException(status_code=404, detail=f"ID为 {img_id} 的记录未找到。")
|
|
|
|
|
|
|
|
- json_data = json.loads(result[0])
|
|
|
|
|
- return JSONResponse(content=json_data)
|
|
|
|
|
|
|
+ # result[0] 已经是经过 IFNULL 处理后的目标 JSON 字符串
|
|
|
|
|
+ json_to_return = json.loads(result[0])
|
|
|
|
|
+
|
|
|
|
|
+ return JSONResponse(content=json_to_return)
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
logger.error(f"获取JSON失败 ({img_id}): {e}")
|
|
logger.error(f"获取JSON失败 ({img_id}): {e}")
|
|
|
if isinstance(e, HTTPException): raise e
|
|
if isinstance(e, HTTPException): raise e
|