Przeglądaj źródła

数据库增加一列json, 原来的作为原生数据

AnlaAnla 2 miesięcy temu
rodzic
commit
2b183e1ccf

+ 7 - 0
.idea/deployment.xml

@@ -3,6 +3,13 @@
   <component name="PublishConfigData" remoteFilesAllowedToDisappearOnAutoupload="false">
     <serverData>
       <paths name="192.168.31.243">
+        <serverdata>
+          <mappings>
+            <mapping deploy="/media/martin/DATA/_ML/RemoteProject/CardScoreDataServer" local="$PROJECT_DIR$" web="/" />
+          </mappings>
+        </serverdata>
+      </paths>
+      <paths name="martin@192.168.77.66:22 password">
         <serverdata>
           <mappings>
             <mapping local="$PROJECT_DIR$" web="/" />

+ 1 - 0
.idea/encodings.xml

@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="Encoding">
+    <file url="file://$PROJECT_DIR$/Test/test01.py" charset="GBK" />
     <file url="PROJECT" charset="GBK" />
   </component>
 </project>

+ 27 - 0
Test/test01.py

@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+import requests
+
+url = 'http://192.168.31.243:7745/api/image_data/data_list'
+params = {
+    'start_id': 5,
+    'end_id': 9,
+    'skip': 0,
+    'limit': 100
+}
+headers = {
+    'accept': 'application/json'
+}
+
+
+
+try:
+    response = requests.get(url, params=params, headers=headers)
+    response.raise_for_status()
+
+    # 打印响应内容
+    print("Status Code:", response.status_code)
+    print("Response JSON:", response.json()) # 如果响应是JSON格式
+    # print("Response Text:", response.text) # 如果响应是纯文本
+
+except requests.exceptions.RequestException as e:
+    print(f"An error occurred: {e}")

+ 13 - 0
Test/数据库测试.py

@@ -0,0 +1,13 @@
+from app.core.config import settings
+import mysql.connector
+
+if __name__ == '__main__':
+    cnx = mysql.connector.connect(**settings.DATABASE_CONFIG_WITH_DB)
+    cursor = cnx.cursor()
+
+
+    query = f"SELECT IFNULL(img_name, img_result_json) AS img_result_json FROM {settings.DB_TABLE_NAME} WHERE img_id = %s"
+    cursor.execute(query, (3,))
+    result = cursor.fetchone()
+
+    print(result)

+ 15 - 43
app/api/image_data.py

@@ -6,11 +6,11 @@ from typing import Optional, Dict, Any, List
 
 from fastapi import APIRouter, File, UploadFile, Depends, HTTPException, Form, Query
 from fastapi.responses import JSONResponse, FileResponse
-from pydantic import BaseModel, field_validator
 from mysql.connector.pooling import PooledMySQLConnection
 
 from app.core.config import settings
 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
 
 # --- 初始化 ---
@@ -21,40 +21,6 @@ router = APIRouter()
 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 接口实现 ---
 
 #  1: 存储图片和JSON数据
@@ -217,8 +183,6 @@ def get_records_by_name(img_name: str, db_conn: PooledMySQLConnection = db_depen
             cursor.close()
 
 
-# ... (其他接口代码保持不变) ...
-
 #  5: 修改JSON数据
 @router.put("/update/json/{img_id}", status_code=200, summary="5. 修改指定ID记录的JSON数据")
 def update_record_json(
@@ -231,7 +195,7 @@ def update_record_json(
     try:
         cursor = db_conn.cursor()
         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))
 
         if cursor.rowcount == 0:
@@ -282,18 +246,26 @@ def get_image_file(img_id: int, db_conn: PooledMySQLConnection = db_dependency):
 #  7: 获取JSON数据
 @router.get("/json/{img_id}", summary="7. 获取指定ID的JSON数据")
 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
     try:
         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,))
-        result = cursor.fetchone()
+        result = cursor.fetchone()  # result will be a tuple like ('{"key": "value"}',)
         if not result:
             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:
         logger.error(f"获取JSON失败 ({img_id}): {e}")
         if isinstance(e, HTTPException): raise e

+ 1 - 0
app/core/database_loader.py

@@ -34,6 +34,7 @@ def init_database():
             "  `img_name` VARCHAR(255) NULL,"
             "  `img_path` VARCHAR(512) NOT NULL,"
             "  `img_result_json` JSON NOT NULL,"
+            "  `img_result_json_new` JSON NULL,"
             "  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP"
             ") ENGINE=InnoDB"
         )

+ 49 - 0
app/utils/scheme.py

@@ -0,0 +1,49 @@
+import os
+import uuid
+import json
+from datetime import date, datetime
+from typing import Optional, Dict, Any, List
+from pydantic import BaseModel, field_validator
+
+
+# --- Pydantic 数据模型 ---
+class ImageRecordResponse(BaseModel):
+    """用于API响应的数据模型,确保数据结构一致"""
+    img_id: int
+    img_name: Optional[str] = None
+    img_path: str
+    img_result_json: Dict[str, Any] # 这个字段在响应中代表的是 img_result_json_new 或 img_result_json 的实际值
+    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
+
+
+def map_row_to_model(row: tuple, columns: List[str]) -> ImageRecordResponse:
+    """
+    将数据库查询出的一行数据映射到Pydantic模型。
+    优先使用 img_result_json_new,如果它为 NULL,则使用 img_result_json。
+    """
+    row_dict = dict(zip(columns, row))
+
+    # Pydantic 字段名为 img_result_json
+    if 'img_result_json_new' in row_dict and row_dict['img_result_json_new'] is not None:
+        row_dict['img_result_json'] = row_dict['img_result_json_new']
+
+    # 移除 img_result_json_new 字段,因为它不属于 ImageRecordResponse 模型
+    if 'img_result_json_new' in row_dict:
+        del row_dict['img_result_json_new']
+
+    return ImageRecordResponse(**row_dict)