|
|
@@ -0,0 +1,315 @@
|
|
|
+# Models 模块
|
|
|
+
|
|
|
+数据库模型模块,用于同步数据库表设计,提供 ORM 支持。
|
|
|
+
|
|
|
+## 目录结构
|
|
|
+
|
|
|
+```
|
|
|
+src/models/
|
|
|
+├── __init__.py # 模块导出
|
|
|
+├── database.py # 数据库配置和连接管理
|
|
|
+├── decode_video.py # DecodeVideo 模型
|
|
|
+└── README.md # 本文件
|
|
|
+```
|
|
|
+
|
|
|
+## 环境变量配置
|
|
|
+
|
|
|
+在使用模型之前,需要配置以下环境变量(如果使用默认配置,则无需设置):
|
|
|
+
|
|
|
+```bash
|
|
|
+# 数据库配置(使用外网地址)
|
|
|
+export DB_HOST=rm-t4nh1xx6o2a6vj8qu3o.mysql.singapore.rds.aliyuncs.com # 数据库主机(默认已配置)
|
|
|
+export DB_PORT=3306 # 数据库端口(默认: 3306)
|
|
|
+export DB_USER=content_rw # 数据库用户名(默认已配置)
|
|
|
+export DB_PASSWORD=bC1aH4bA1lB0 # 数据库密码(默认已配置)
|
|
|
+export DB_NAME=content-deconstruction # 数据库名称(默认已配置)
|
|
|
+```
|
|
|
+
|
|
|
+或者在 `.env` 文件中配置:
|
|
|
+
|
|
|
+```env
|
|
|
+# 使用外网地址访问数据库
|
|
|
+DB_HOST=rm-t4nh1xx6o2a6vj8qu3o.mysql.singapore.rds.aliyuncs.com
|
|
|
+DB_PORT=3306
|
|
|
+DB_USER=content_rw
|
|
|
+DB_PASSWORD=bC1aH4bA1lB0
|
|
|
+DB_NAME=content-deconstruction
|
|
|
+
|
|
|
+# 如需使用内网地址,可切换为:
|
|
|
+# DB_HOST=rm-t4nh1xx6o2a6vj8qu.mysql.singapore.rds.aliyuncs.com
|
|
|
+```
|
|
|
+
|
|
|
+**注意**:代码中已配置默认值,可以直接使用。如需覆盖,可通过环境变量设置。
|
|
|
+
|
|
|
+## 快速开始
|
|
|
+
|
|
|
+### 1. 初始化数据库
|
|
|
+
|
|
|
+```python
|
|
|
+from src.models import init_db
|
|
|
+
|
|
|
+# 创建所有表(如果不存在)
|
|
|
+init_db()
|
|
|
+```
|
|
|
+
|
|
|
+### 2. 使用模型
|
|
|
+
|
|
|
+#### 创建记录
|
|
|
+
|
|
|
+```python
|
|
|
+from src.models import get_db, DecodeVideo, DecodeStatus
|
|
|
+
|
|
|
+# 获取数据库会话
|
|
|
+db = next(get_db())
|
|
|
+
|
|
|
+# 创建新记录
|
|
|
+video = DecodeVideo.create(
|
|
|
+ task_id=12345,
|
|
|
+ video_id="58840748",
|
|
|
+ status=DecodeStatus.PENDING
|
|
|
+)
|
|
|
+
|
|
|
+# 保存到数据库
|
|
|
+db.add(video)
|
|
|
+db.commit()
|
|
|
+db.close()
|
|
|
+```
|
|
|
+
|
|
|
+#### 查询记录
|
|
|
+
|
|
|
+```python
|
|
|
+from src.models import get_db, DecodeVideo, DecodeStatus
|
|
|
+
|
|
|
+db = next(get_db())
|
|
|
+
|
|
|
+# 根据 task_id 查询
|
|
|
+video = db.query(DecodeVideo).filter_by(task_id=12345).first()
|
|
|
+
|
|
|
+# 根据 video_id 查询
|
|
|
+videos = db.query(DecodeVideo).filter_by(video_id="58840748").all()
|
|
|
+
|
|
|
+# 根据状态查询
|
|
|
+pending_videos = db.query(DecodeVideo).filter_by(status=DecodeStatus.PENDING).all()
|
|
|
+
|
|
|
+# 查询所有记录
|
|
|
+all_videos = db.query(DecodeVideo).all()
|
|
|
+
|
|
|
+db.close()
|
|
|
+```
|
|
|
+
|
|
|
+#### 更新记录
|
|
|
+
|
|
|
+```python
|
|
|
+from src.models import get_db, DecodeVideo, DecodeStatus
|
|
|
+
|
|
|
+db = next(get_db()
|
|
|
+
|
|
|
+# 查询记录
|
|
|
+video = db.query(DecodeVideo).filter_by(task_id=12345).first()
|
|
|
+
|
|
|
+if video:
|
|
|
+ # 更新状态
|
|
|
+ video.update_status(DecodeStatus.EXECUTING)
|
|
|
+
|
|
|
+ # 更新结果
|
|
|
+ video.update_result('{"result": "..."}')
|
|
|
+
|
|
|
+ # 或者直接更新字段
|
|
|
+ video.status = DecodeStatus.SUCCESS
|
|
|
+ video.result = '{"result": "..."}'
|
|
|
+
|
|
|
+ db.commit()
|
|
|
+
|
|
|
+db.close()
|
|
|
+```
|
|
|
+
|
|
|
+#### 删除记录
|
|
|
+
|
|
|
+```python
|
|
|
+from src.models import get_db, DecodeVideo
|
|
|
+
|
|
|
+db = next(get_db())
|
|
|
+
|
|
|
+video = db.query(DecodeVideo).filter_by(task_id=12345).first()
|
|
|
+if video:
|
|
|
+ db.delete(video)
|
|
|
+ db.commit()
|
|
|
+
|
|
|
+db.close()
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 使用上下文管理器(推荐)
|
|
|
+
|
|
|
+```python
|
|
|
+from contextlib import contextmanager
|
|
|
+from src.models import get_db, DecodeVideo, DecodeStatus
|
|
|
+
|
|
|
+@contextmanager
|
|
|
+def db_session():
|
|
|
+ """数据库会话上下文管理器"""
|
|
|
+ db = next(get_db())
|
|
|
+ try:
|
|
|
+ yield db
|
|
|
+ db.commit()
|
|
|
+ except Exception:
|
|
|
+ db.rollback()
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ db.close()
|
|
|
+
|
|
|
+# 使用示例
|
|
|
+with db_session() as db:
|
|
|
+ video = DecodeVideo.create(
|
|
|
+ task_id=12345,
|
|
|
+ video_id="58840748",
|
|
|
+ status=DecodeStatus.PENDING
|
|
|
+ )
|
|
|
+ db.add(video)
|
|
|
+ # 自动提交和关闭
|
|
|
+```
|
|
|
+
|
|
|
+## 模型说明
|
|
|
+
|
|
|
+### DecodeVideo
|
|
|
+
|
|
|
+对应数据库表 `decode_videos`
|
|
|
+
|
|
|
+#### 字段
|
|
|
+
|
|
|
+- `task_id` (BigInteger, Primary Key): 任务ID,非空
|
|
|
+- `video_id` (String(100)): 视频ID,可为空,已建立索引
|
|
|
+- `result` (Text): 解码结果(JSON 格式),可为空
|
|
|
+- `status` (Integer): 状态,可为空,默认值为 0(待执行),已建立索引
|
|
|
+ - 0: 待执行 (PENDING)
|
|
|
+ - 1: 执行中 (EXECUTING)
|
|
|
+ - 2: 执行成功 (SUCCESS)
|
|
|
+ - 3: 执行失败 (FAILED)
|
|
|
+- `error_reason` (Text): 失败原因,可为空
|
|
|
+- `created_at` (DateTime): 创建时间,自动设置
|
|
|
+- `updated_at` (DateTime): 更新时间,自动更新
|
|
|
+
|
|
|
+#### 方法
|
|
|
+
|
|
|
+- `to_dict()`: 将模型转换为字典
|
|
|
+- `create()`: 类方法,创建新实例
|
|
|
+- `update_status()`: 更新状态
|
|
|
+- `update_result()`: 更新解码结果
|
|
|
+
|
|
|
+### DecodeStatus
|
|
|
+
|
|
|
+状态枚举类
|
|
|
+
|
|
|
+```python
|
|
|
+DecodeStatus.PENDING # 0 - 待执行
|
|
|
+DecodeStatus.EXECUTING # 1 - 执行中
|
|
|
+DecodeStatus.SUCCESS # 2 - 执行成功
|
|
|
+DecodeStatus.FAILED # 3 - 执行失败
|
|
|
+```
|
|
|
+
|
|
|
+## 完整示例
|
|
|
+
|
|
|
+```python
|
|
|
+#!/usr/bin/env python
|
|
|
+# -*- coding: utf-8 -*-
|
|
|
+"""
|
|
|
+使用 DecodeVideo 模型的完整示例
|
|
|
+"""
|
|
|
+
|
|
|
+from contextlib import contextmanager
|
|
|
+from src.models import get_db, DecodeVideo, DecodeStatus, init_db
|
|
|
+
|
|
|
+@contextmanager
|
|
|
+def db_session():
|
|
|
+ """数据库会话上下文管理器"""
|
|
|
+ db = next(get_db())
|
|
|
+ try:
|
|
|
+ yield db
|
|
|
+ db.commit()
|
|
|
+ except Exception:
|
|
|
+ db.rollback()
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ db.close()
|
|
|
+
|
|
|
+
|
|
|
+def main():
|
|
|
+ # 1. 初始化数据库(首次使用)
|
|
|
+ init_db()
|
|
|
+
|
|
|
+ # 2. 创建新记录
|
|
|
+ with db_session() as db:
|
|
|
+ video = DecodeVideo.create(
|
|
|
+ task_id=12345,
|
|
|
+ video_id="58840748",
|
|
|
+ status=DecodeStatus.PENDING
|
|
|
+ )
|
|
|
+ db.add(video)
|
|
|
+ print(f"创建记录: {video}")
|
|
|
+
|
|
|
+ # 3. 查询记录
|
|
|
+ with db_session() as db:
|
|
|
+ video = db.query(DecodeVideo).filter_by(task_id=12345).first()
|
|
|
+ if video:
|
|
|
+ print(f"查询结果: {video.to_dict()}")
|
|
|
+
|
|
|
+ # 4. 更新状态
|
|
|
+ with db_session() as db:
|
|
|
+ video = db.query(DecodeVideo).filter_by(task_id=12345).first()
|
|
|
+ if video:
|
|
|
+ video.update_status(DecodeStatus.EXECUTING)
|
|
|
+ print(f"更新状态为: {DecodeStatus.get_description(video.status)}")
|
|
|
+
|
|
|
+ # 5. 更新结果
|
|
|
+ with db_session() as db:
|
|
|
+ video = db.query(DecodeVideo).filter_by(task_id=12345).first()
|
|
|
+ if video:
|
|
|
+ result = '{"result": "解码成功"}'
|
|
|
+ video.update_result(result)
|
|
|
+ print(f"更新结果: {video.result}")
|
|
|
+
|
|
|
+ # 6. 查询所有待执行的记录
|
|
|
+ with db_session() as db:
|
|
|
+ pending_videos = db.query(DecodeVideo).filter_by(
|
|
|
+ status=DecodeStatus.PENDING
|
|
|
+ ).all()
|
|
|
+ print(f"待执行任务数: {len(pending_videos)}")
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ main()
|
|
|
+```
|
|
|
+
|
|
|
+## 注意事项
|
|
|
+
|
|
|
+1. **数据库连接**: 使用 `get_db()` 获取数据库会话后,务必在最后调用 `db.close()` 关闭连接
|
|
|
+2. **事务管理**: 修改数据后需要调用 `db.commit()` 提交事务,出错时调用 `db.rollback()` 回滚
|
|
|
+3. **环境变量**: 确保正确配置数据库连接相关的环境变量
|
|
|
+4. **表结构同步**: 如果数据库表结构发生变化,需要更新模型定义以保持同步
|
|
|
+5. **索引**: `video_id` 和 `status` 字段已建立索引,适合用于查询条件
|
|
|
+
|
|
|
+## 与工作流集成
|
|
|
+
|
|
|
+可以在工作流中使用模型来保存和查询解码结果:
|
|
|
+
|
|
|
+```python
|
|
|
+from src.models import get_db, DecodeVideo, DecodeStatus
|
|
|
+
|
|
|
+def save_decode_result(task_id: int, video_id: str, result: dict):
|
|
|
+ """保存解码结果到数据库"""
|
|
|
+ db = next(get_db())
|
|
|
+ try:
|
|
|
+ video = db.query(DecodeVideo).filter_by(task_id=task_id).first()
|
|
|
+ if not video:
|
|
|
+ video = DecodeVideo.create(task_id=task_id, video_id=video_id)
|
|
|
+ db.add(video)
|
|
|
+
|
|
|
+ import json
|
|
|
+ video.update_result(json.dumps(result, ensure_ascii=False))
|
|
|
+ db.commit()
|
|
|
+ except Exception as e:
|
|
|
+ db.rollback()
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ db.close()
|
|
|
+```
|
|
|
+
|