# 数据模型 **本文档引用的文件** - [backend/app/models/__init__.py](file://backend/app/models/__init__.py) - [backend/app/models/user.py](file://backend/app/models/user.py) - [backend/app/models/query.py](file://backend/app/models/query.py) - [backend/app/models/query_task.py](file://backend/app/models/query_task.py) - [backend/app/models/citation_record.py](file://backend/app/models/citation_record.py) - [backend/app/models/subscription.py](file://backend/app/models/subscription.py) - [backend/app/database.py](file://backend/app/database.py) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py) - [backend/app/schemas/query.py](file://backend/app/schemas/query.py) - [backend/app/schemas/citation.py](file://backend/app/schemas/citation.py) - [backend/app/services/query.py](file://backend/app/services/query.py) - [backend/app/api/queries.py](file://backend/app/api/queries.py) - [backend/app/services/citation.py](file://backend/app/services/citation.py) - [backend/app/api/citations.py](file://backend/app/api/citations.py) - [backend/app/config.py](file://backend/app/config.py) - [backend/app/api/deps.py](file://backend/app/api/deps.py) ## 更新摘要 **所做更改** - 完善了用户模型的字段映射和关系配置说明 - 详细补充了查询模型的索引策略和生命周期管理 - 新增了查询任务模型的状态机和任务调度机制 - 完善了引用记录模型的统计分析功能说明 - 补充了订阅模型的支付信息字段和状态管理 - 增强了模型间关系映射和级联策略的技术细节 - 完善了序列化、反序列化与数据验证机制 - 新增了使用示例和最佳实践指南 ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考量](#性能考量) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本文件系统性梳理 GEO 平台的 SQLAlchemy ORM 数据模型,覆盖模型类定义、字段映射与关系配置,解释模型间的关系映射(含级联与外键约束)、序列化/反序列化与数据验证机制、生命周期管理与事件钩子、以及使用示例与最佳实践。目标是帮助开发者快速理解并正确使用数据模型,确保在查询、任务调度、引用记录与订阅管理等场景中保持一致性与可维护性。 ## 项目结构 后端采用异步 SQLAlchemy(SQLAlchemy 2.x + asyncpg)与 Pydantic 模式进行数据建模与 API 层交互。数据库初始化通过 declarative_base 创建基类,迁移脚本由 Alembic 管理,模型导出统一在 models 包的 __init__.py 中聚合。 ```mermaid graph TB subgraph "模型层" U["User
用户"] Q["Query
查询任务"] QT["QueryTask
查询任务执行单元"] CR["CitationRecord
引用记录"] S["Subscription
订阅"] end subgraph "数据库" DB["PostgreSQL"] end subgraph "服务层" SVCQ["Query 服务"] SVCC["Citation 服务"] end subgraph "API 层" APIQ["Queries API"] APIC["Citations API"] end U --> Q Q --> CR Q --> QT U --> S SVCQ --> Q SVCC --> CR APIQ --> SVCQ APIC --> SVCC Q --- DB CR --- DB QT --- DB S --- DB U --- DB ``` **图表来源** - [backend/app/models/user.py:11-41](file://backend/app/models/user.py#L11-L41) - [backend/app/models/query.py:11-55](file://backend/app/models/query.py#L11-L55) - [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39) - [backend/app/models/citation_record.py:11-42](file://backend/app/models/citation_record.py#L11-L42) - [backend/app/models/subscription.py:11-37](file://backend/app/models/subscription.py#L11-L37) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/app/services/query.py:1-123](file://backend/app/services/query.py#L1-L123) - [backend/app/services/citation.py:1-359](file://backend/app/services/citation.py#L1-L359) - [backend/app/api/queries.py:1-86](file://backend/app/api/queries.py#L1-L86) - [backend/app/api/citations.py:1-78](file://backend/app/api/citations.py#L1-L78) **章节来源** - [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14) - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) ## 核心组件 本节概述各模型的职责、关键字段与关系,为后续深入分析打基础。 - 用户(User) - 负责平台用户信息与配额控制,支持计划类型与最大查询数限制。 - 关系:一对多到 Query、Subscription,删除时级联删除孤儿对象。 - 查询(Query) - 描述关键词、目标品牌、别名、平台集合、频率、状态及下次查询时间等。 - 关系:多对一到 User;一对多到 CitationRecord、QueryTask;删除时级联删除孤儿对象。 - 查询任务(QueryTask) - 记录单次平台查询任务的状态、错误信息与时间戳。 - 关系:多对一到 Query;删除时级联删除。 - 引用记录(CitationRecord) - 记录某次查询在特定平台上的引用情况、竞品品牌列表与原始响应摘要。 - 关系:多对一到 Query;删除时级联删除。 - 订阅(Subscription) - 记录用户的订阅计划、有效期、支付信息与状态。 - 关系:多对一到 User;删除时级联删除。 **章节来源** - [backend/app/models/user.py:11-41](file://backend/app/models/user.py#L11-L41) - [backend/app/models/query.py:11-55](file://backend/app/models/query.py#L11-L55) - [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39) - [backend/app/models/citation_record.py:11-42](file://backend/app/models/citation_record.py#L11-L42) - [backend/app/models/subscription.py:11-37](file://backend/app/models/subscription.py#L11-L37) ## 架构总览 下图展示模型与数据库表、索引、外键约束之间的对应关系,以及服务层与 API 层如何通过模型进行数据访问。 ```mermaid erDiagram USERS { uuid id PK string email UK string password_hash string name string plan integer max_queries boolean is_active timestamptz created_at timestamptz updated_at } QUERIES { uuid id PK uuid user_id FK string keyword string target_brand jsonb brand_aliases jsonb platforms string frequency string status timestamptz last_queried_at timestamptz next_query_at timestamptz created_at timestamptz updated_at } CITATION_RECORDS { uuid id PK uuid query_id FK string platform boolean cited integer citation_position text citation_text jsonb competitor_brands text raw_response timestamptz queried_at } QUERY_TASKS { uuid id PK uuid query_id FK string platform string status text error_message timestamptz scheduled_at timestamptz started_at timestamptz completed_at } SUBSCRIPTIONS { uuid id PK uuid user_id FK string plan string status date start_date date end_date numeric amount string payment_method string payment_id timestamptz created_at } USERS ||--o{ QUERIES : "拥有" USERS ||--o{ SUBSCRIPTIONS : "拥有" QUERIES ||--o{ CITATION_RECORDS : "产生" QUERIES ||--o{ QUERY_TASKS : "拆分执行" ``` **图表来源** - [backend/alembic/versions/488d0bd5ab01_initial_migration.py:21-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L21-L128) - [backend/app/models/user.py:11-41](file://backend/app/models/user.py#L11-L41) - [backend/app/models/query.py:11-55](file://backend/app/models/query.py#L11-L55) - [backend/app/models/citation_record.py:11-42](file://backend/app/models/citation_record.py#L11-L42) - [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39) - [backend/app/models/subscription.py:11-37](file://backend/app/models/subscription.py#L11-L37) ## 详细组件分析 ### 用户模型(User) - 表名与主键 - 表名:users;主键:UUID 类型的 id。 - 字段映射 - 邮箱唯一且必填;密码哈希必填;名称可空;计划默认 free;最大查询数默认 5;激活状态默认 true;创建/更新时间自动填充。 - 关系 - 一对多到 Query、Subscription,删除用户时级联删除孤儿对象。 - 生命周期与事件 - created_at/updated_at 使用 server_default/onupdate 注入数据库侧时间戳。 - 序列化/反序列化 - 通过 Pydantic 模型(如查询响应)在 API 层进行序列化;ORM 对象可直接用于 FastAPI 响应模型(from_attributes)。 - 最佳实践 - 在创建/更新用户时避免直接修改计划或配额,建议通过专门的服务接口进行校验与审计。 **章节来源** - [backend/app/models/user.py:11-41](file://backend/app/models/user.py#L11-L41) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py:23-37](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L23-L37) ### 查询模型(Query) - 表名与主键 - 表名:queries;主键:UUID 类型的 id。 - 字段映射 - 外键 user_id 指向 users.id,删除时级联;关键词与目标品牌必填;品牌别名与平台集合默认值合理;频率默认 weekly;状态默认 active;下次查询时间可空;创建/更新时间自动填充。 - 关系 - 多对一到 User;一对多到 CitationRecord、QueryTask,删除查询时级联删除孤儿对象。 - 索引 - 为 user_id、status、next_query_at 建立索引以优化查询。 - 生命周期与事件 - created_at/updated_at 使用 server_default/onupdate 注入数据库侧时间戳。 - 序列化/反序列化 - 响应模型 QueryResponse 支持 from_attributes,便于 ORM 对象直接转为 API 响应。 - 最佳实践 - 更新频率时同步更新 next_query_at;在创建查询前检查用户配额。 **章节来源** - [backend/app/models/query.py:11-55](file://backend/app/models/query.py#L11-L55) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py:39-59](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L39-L59) ### 查询任务模型(QueryTask) - 表名与主键 - 表名:query_tasks;主键:UUID 类型的 id。 - 字段映射 - 外键 query_id 指向 queries.id,删除时级联;平台必填;状态默认 pending;错误信息可空;调度/开始/完成时间可空。 - 关系 - 多对一到 Query;删除查询任务时级联删除。 - 索引 - 为 status 建立索引以支持任务调度筛选。 - 生命周期与事件 - scheduled_at 默认当前时间;其他时间戳按需更新。 - 序列化/反序列化 - 通过 Pydantic 模型进行 API 层序列化。 - 最佳实践 - 任务状态机:pending -> started -> completed 或 failed;失败时记录 error_message。 **章节来源** - [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py:80-94](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L80-L94) ### 引用记录模型(CitationRecord) - 表名与主键 - 表名:citation_records;主键:UUID 类型的 id。 - 字段映射 - 外键 query_id 指向 queries.id,删除时级联;平台必填;是否引用默认 false;引用位置可空;引用文本可空;竞品品牌列表默认空数组;原始响应可空;查询时间默认当前时间。 - 关系 - 多对一到 Query;删除查询时级联删除。 - 索引 - 为 query_id、queried_at、platform 建立索引以优化统计与检索。 - 生命周期与事件 - queried_at 默认当前时间。 - 序列化/反序列化 - 通过 CitationResponse 进行 API 层序列化。 - 最佳实践 - 统计时按平台与日期聚合,结合索引提升性能。 **章节来源** - [backend/app/models/citation_record.py:11-42](file://backend/app/models/citation_record.py#L11-L42) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py:61-78](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L61-L78) ### 订阅模型(Subscription) - 表名与主键 - 表名:subscriptions;主键:UUID 类型的 id。 - 字段映射 - 外键 user_id 指向 users.id,删除时级联;计划必填;状态默认 active;起止日期必填;金额可空;支付方式与支付 ID 可空;创建时间默认当前时间。 - 关系 - 多对一到 User;删除用户时级联删除。 - 生命周期与事件 - created_at 默认当前时间。 - 序列化/反序列化 - 通过 Pydantic 模型进行 API 层序列化。 - 最佳实践 - 订阅到期后应自动调整用户配额与功能权限。 **章节来源** - [backend/app/models/subscription.py:11-37](file://backend/app/models/subscription.py#L11-L37) - [backend/alembic/versions/488d0bd5ab01_initial_migration.py:96-111](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L96-L111) ### 模型关系与级联策略 - 外键约束 - 所有子表均设置外键指向父表主键,并在删除时采用 CASCADE,确保数据一致性。 - 级联删除孤儿对象 - User 的 queries、subscriptions;Query 的 citation_records、query_tasks 均配置了"all, delete-orphan",保证删除父对象时自动清理其子对象。 - 索引策略 - 查询高频字段(如 user_id、status、next_query_at、queried_at、platform)建立索引,提升查询性能。 **章节来源** - [backend/app/models/user.py:35-40](file://backend/app/models/user.py#L35-L40) - [backend/app/models/query.py:43-48](file://backend/app/models/query.py#L43-L48) - [backend/app/models/query_task.py:36-38](file://backend/app/models/query_task.py#L36-L38) - [backend/app/models/citation_record.py:37-41](file://backend/app/models/citation_record.py#L37-L41) ### 序列化、反序列化与数据验证 - Pydantic 验证 - 查询创建/更新请求体包含平台集合、频率、状态等字段的严格校验,非法值会抛出异常。 - ORM 到 API 的转换 - 响应模型启用 from_attributes,允许直接将 ORM 对象转为 JSON 响应。 - API 层集成 - Queries API 将请求体绑定到 Pydantic 模型,调用服务层进行业务处理,再返回 ORM 对象或 Pydantic 响应模型。 **章节来源** - [backend/app/schemas/query.py:11-94](file://backend/app/schemas/query.py#L11-L94) - [backend/app/schemas/citation.py:7-50](file://backend/app/schemas/citation.py#L7-L50) - [backend/app/api/queries.py:1-86](file://backend/app/api/queries.py#L1-L86) ### 生命周期管理与事件钩子 - 时间戳管理 - 所有模型的 created_at/updated_at 使用 server_default/onupdate 注入数据库侧时间戳,减少应用层负担。 - 任务状态流转 - QueryTask 的状态从 pending 到 started 再到 completed 或 failed,配合 scheduled_at/started_at/completed_at 字段记录生命周期节点。 - 查询调度 - 服务层根据频率计算 next_query_at,便于定时任务调度。 **章节来源** - [backend/app/models/user.py:25-33](file://backend/app/models/user.py#L25-L33) - [backend/app/models/query.py:32-40](file://backend/app/models/query.py#L32-L40) - [backend/app/models/query_task.py:27-32](file://backend/app/models/query_task.py#L27-L32) - [backend/app/services/query.py:62-77](file://backend/app/services/query.py#L62-L77) ### 使用示例与最佳实践 - 创建查询 - 步骤:校验用户配额 -> 计算 next_query_at -> 构造 Query -> 提交事务 -> 刷新对象。 - 参考路径:[创建查询服务:45-81](file://backend/app/services/query.py#L45-L81) - 更新查询 - 步骤:读取查询 -> 排除未设置字段 -> 若更新频率则重算 next_query_at -> 提交事务 -> 刷新对象。 - 参考路径:[更新查询服务:84-113](file://backend/app/services/query.py#L84-L113) - 删除查询 - 步骤:按用户与查询 ID 定位 -> 删除 -> 提交事务。 - 参考路径:[删除查询服务:116-129](file://backend/app/services/query.py#L116-L129) - API 调用 - GET /queries -> 返回 QueryListResponse - POST /queries -> 返回 QueryResponse - GET /queries/{query_id} -> 返回 QueryResponse - PUT /queries/{query_id} -> 返回 QueryResponse - DELETE /queries/{query_id} -> 204 No Content - 参考路径:[查询 API:15-86](file://backend/app/api/queries.py#L15-L86) **章节来源** - [backend/app/services/query.py:45-129](file://backend/app/services/query.py#L45-L129) - [backend/app/api/queries.py:15-86](file://backend/app/api/queries.py#L15-L86) ## 依赖关系分析 - 数据库引擎与会话 - 使用异步引擎与 async_sessionmaker,Base 作为 declarative_base 基类。 - 模型导出 - models/__init__.py 统一导出所有模型,便于上层模块按需导入。 - 迁移脚本 - Alembic 初始迁移脚本定义了表结构、索引与外键约束,与模型定义保持一致。 ```mermaid graph LR CFG["配置
DATABASE_URL"] --> ENG["异步引擎"] ENG --> SESS["AsyncSessionLocal"] SESS --> BASE["declarative_base"] BASE --> MODELS["模型类"] MODELS --> DB["PostgreSQL"] ``` **图表来源** - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/app/config.py](file://backend/app/config.py#L7) **章节来源** - [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29) - [backend/app/config.py:1-23](file://backend/app/config.py#L1-L23) ## 性能考量 - 索引设计 - queries:user_id、status、next_query_at - citation_records:query_id、queried_at、platform - query_tasks:status - 建议:基于实际查询模式持续评估与补充索引。 - 查询优化 - 使用 select + order_by + offset + limit 实现分页与排序。 - 使用 func.count 统计总数,避免不必要的全量加载。 - 异步 I/O - 使用 asyncpg 与 SQLAlchemy 异步引擎,降低并发场景下的阻塞风险。 - 缓存策略 - 对热点查询结果(如用户配额、订阅状态)可引入 Redis 缓存,减少数据库压力。 ## 故障排查指南 - 查询配额超限 - 现象:创建查询时报错"PermissionError: Query limit exceeded" - 处理:检查用户 max_queries 与当前查询数量,必要时升级计划或清理历史查询。 - 参考路径:[创建查询服务:45-81](file://backend/app/services/query.py#L45-L81) - 查询不存在 - 现象:GET/PUT/DELETE 查询返回 404 - 处理:确认 query_id 与当前用户匹配;检查软删除/级联删除是否生效。 - 参考路径:[查询 API:42-85](file://backend/app/api/queries.py#L42-L85) - 平台/频率参数非法 - 现象:Pydantic 校验失败 - 处理:核对平台集合是否在允许集合内,频率是否为 daily/weekly。 - 参考路径:[查询请求体校验:18-33](file://backend/app/schemas/query.py#L18-L33) - 任务状态异常 - 现象:任务长时间 pending 或失败 - 处理:检查 error_message 字段;核对平台可用性与 API 密钥配置。 - 参考路径:[查询任务模型:11-39](file://backend/app/models/query_task.py#L11-L39) **章节来源** - [backend/app/services/query.py:45-129](file://backend/app/services/query.py#L45-L129) - [backend/app/api/queries.py:42-85](file://backend/app/api/queries.py#L42-L85) - [backend/app/schemas/query.py:18-33](file://backend/app/schemas/query.py#L18-L33) - [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39) ## 结论 GEO 项目的数据模型围绕用户、查询、任务、引用记录与订阅五大实体构建,采用异步 SQLAlchemy ORM 与 Alembic 迁移管理,配合 Pydantic 的输入输出验证,形成清晰的领域模型与 API 边界。通过合理的外键约束、级联策略与索引设计,既保证了数据一致性,也兼顾了查询性能。建议在生产环境中持续监控查询性能与缓存命中率,并完善事件钩子与审计日志以增强可观测性。 ## 附录 - 数据库连接配置 - DATABASE_URL:PostgreSQL 异步连接字符串 - 参考路径:[配置](file://backend/app/config.py#L12) - 模型导出入口 - models/__init__.py 统一导出所有模型 - 参考路径:[模型导出:1-14](file://backend/app/models/__init__.py#L1-L14) - JWT 认证配置 - JWT_SECRET:JWT 密钥 - JWT_EXPIRE_HOURS:JWT 过期时间(小时) - 参考路径:[认证依赖:16-43](file://backend/app/api/deps.py#L16-L43)