# ExamService 题库小程序服务端 - FastAPI实现 ## 项目结构 ``` ExamService/ ├── alembic/ # 数据库迁移相关 ├── mooc/ # 主应用目录 │ ├── api/ # API路由 │ │ └── v1/ # API v1版本 │ ├── core/ # 核心配置 │ ├── crud/ # 数据库操作 │ ├── db/ # 数据库 │ ├── models/ # 数据库模型 │ ├── schemas/ # Pydantic模型 │ └── utils/ # 工具函数 ├── tests/ # 测试目录 └── [配置文件] ``` ## 安装 ### 1. 安装 Miniconda 在 Ubuntu 上安装 Miniconda,执行以下步骤: ```bash # 下载 Miniconda 安装脚本 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh # 给安装脚本添加执行权限 chmod +x Miniconda3-latest-Linux-x86_64.sh # 运行安装脚本 ./Miniconda3-latest-Linux-x86_64.sh # 按照提示完成安装,选择安装目录并接受许可协议 # 激活 Miniconda source ~/.bashrc # 创建名为 'mooc' 的虚拟环境,Python 版本大于等于 3.13 conda create --name mooc python>=3.13 # 激活 'mooc' 环境 conda activate mooc # 安装依赖 pip install -r requirements.txt ``` ### 安装mysql开发库 ```bash # 更新包列表 apt-get update # 安装 MySQL 开发包和其他必要的包 apt-get install -y python3-dev default-libmysqlclient-dev build-essential pkg-config pip install mysqlclient pymysql cryptography ``` ## 运行 ```bash uvicorn main:app --reload ``` ## 初始化数据库 ```bash alembic init alembic alembic revision --autogenerate -m "Initial migration" alembic upgrade head ``` ## 添加数据库表 ### 1.创建模型文件: **因为表格太多,可以把同类型表放在同一个文件,文件命名规则:ims_account_wechats、ims_account_wxapp、ims_account_xzapp等表格去除前缀和后缀,即为account.py** ```python # 这个模型类AccountWechats用于映射ims_account_wechats表: # 1. 在ORM层中代表数据库表结构,方便CRUD操作。 # 2. 在FastAPI中引用该模型时,可以使用Pydantic自动转换ORM对象到响应模型。 # 3. 创建模型时需确保表名(__tablename__)与真实的数据库表名保持一致,否则查询和插入可能失败。 # 4. 字段类型要与数据库中定义的列类型严格匹配,避免出现不兼容或异常。 # 5. 通过Primary Key(acid)唯一标识记录,确保ORM能正确追踪和更新该对象。 # 6. config.orm_mode = True:允许直接把SQLAlchemy模型实例转换为Pydantic模型对象。 # filepath: ExamService/mooc/models/account.py from sqlalchemy import Column, Integer, String, SmallInteger from mooc.db.database import Base # 类名命名规则: 去除ims前缀后采用 帕斯卡命名法,无连接符每个单词手写大写 # AccountWechats模型用于映射数据库表 ims_account_wechats class AccountWechats(Base): __tablename__ = "ims_account_wechats" acid = Column(Integer, primary_key=True) uniacid = Column(Integer, nullable=False) token = Column(String(32), nullable=False) encodingaeskey = Column(String(255), nullable=False) level = Column(SmallInteger, nullable=False) name = Column(String(30), nullable=False) account = Column(String(30), nullable=False) original = Column(String(50), nullable=False) signature = Column(String(100), nullable=False) country = Column(String(10), nullable=False) province = Column(String(3), nullable=False) city = Column(String(15), nullable=False) username = Column(String(30), nullable=False) password = Column(String(32), nullable=False) lastupdate = Column(Integer, nullable=False) key = Column(String(50), nullable=False) secret = Column(String(50), nullable=False) styleid = Column(Integer, nullable=False) subscribeurl = Column(String(120), nullable=False) auth_refresh_token = Column(String(255), nullable=False) class Config: from_attributes = True # 允许与Pydantic的ORM功能兼容,直接读取数据库模型对象 ``` ### 2.创建schema: ```python # filepath: ExamService/mooc/schemas/account.py from pydantic import BaseModel from typing import Optional class AccountWechatsBase(BaseModel): """ 数据模型基类: AccountWechatsBase 用于描述基础字段的类型、用途和注意点。 - 注意: 必填字段都在这里声明,每个字段都对应数据库中的一列。 """ uniacid: int # 微信公众号/小程序的关联ID token: str # 访问接口时使用的token encodingaeskey: str # 用于消息加解密的AES密钥 level: int # 认证等级,如订阅号/服务号 name: str # 微信公众号名称 account: str # 公众号帐号,如微信号 original: str # 原始ID(通常以gh_开头) signature: str # 公众号信息签名 country: str # 国家 province: str # 省份 city: str # 城市 username: str # 后台登录用户名 password: str # 后台登录密码 lastupdate: int # 最后一次更新的时间戳 key: str # 开发者Key secret: str # 开发者Secret styleid: int # 模板样式ID subscribeurl: str # 订阅链接 auth_refresh_token: str # 用来刷新授权的token class AccountWechatsCreate(AccountWechatsBase): """ 用于创建新微信帐号记录: - 继承自AccountWechatsBase, 不额外添加字段 - 仅表示此Schema专用于'创建'场景 """ # 用于创建新记录,包含所有必填字段 pass class AccountWechatsUpdate(BaseModel): """ 用于更新已有微信帐号记录: - 只包含可选字段,未在此处的内容将保持不变 - 注意: exclude_unset=True 可以避免更新空值 """ token: Optional[str] # 可选更新token encodingaeskey: Optional[str]# 可选更新AES key class AccountWechats(AccountWechatsBase): """ 表示完整的微信帐号记录: - acid: 数据库主键ID - 包含所有字段的最终模型,ORM转换时使用 """ acid: int # 表中的主键ID class Config: from_attributes = True # 允许与ORM对象进行直接转换 ``` ### 3.创建 CRUD: ```python # filepath: ExamService/mooc/crud/crud_account.py from typing import Optional from sqlalchemy.orm import Session from mooc.crud.crud_base import CRUDBase from mooc.models.account import AccountWechats from mooc.schemas.account import AccountWechatsCreate, AccountWechatsUpdate class CRUDAccountWechats(CRUDBase[AccountWechats, AccountWechatsCreate, AccountWechatsUpdate]): """ AccountWechats的CRUD操作类 继承自CRUDBase基类,实现基础的增删改查功能 可以根据需要添加自定义的查询方法 """ def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountWechats]: """ 根据uniacid查询微信公众号账号 :param db: 数据库会话 :param uniacid: 统一公众号ID :return: AccountWechats对象或None """ return db.query(self.model).filter(self.model.uniacid == uniacid).first() # 实例化CRUD对象,方便在其他地方直接导入使用 account_wechats = CRUDAccountWechats(AccountWechats) # 使用示例: """ # 创建新记录 new_account = account_wechats.create(db, obj_in=account_create_schema) # 根据ID获取记录 account = account_wechats.get(db, id=1) # 根据uniacid获取记录 account = account_wechats.get_by_uniacid(db, uniacid=100) # 更新记录 updated = account_wechats.update(db, db_obj=existing_account, obj_in=update_data) # 删除记录 account_wechats.remove(db, id=1) """ ``` ### 4.注册模型: ```python # filepath: ExamService/mooc/db/base.py from mooc.db.database import Base from mooc.models.admin import Admin, Account, AccountWebapp from mooc.models.account import AccountWechats # 新增,将创建好的模型类导入即可 ``` ### 5.运行代码更新数据库信息 ```bash python main.py ``` ## CRUDBase 使用指南 ### 简介 CRUDBase是一个通用的CRUD基类,提供了基础的增删改查操作。通过继承这个基类,可以快速实现特定模型的CRUD操作。 ### 使用方法 1. 创建CRUD类: ```python from mooc.crud.base import CRUDBase from mooc.models.your_model import YourModel from mooc.schemas.your_schema import YourCreateSchema, YourUpdateSchema class CRUDYourModel(CRUDBase[YourModel, YourCreateSchema, YourUpdateSchema]): pass # 继承基础功能即可,如需自定义方法可以在这里添加 ``` 2. 实例化CRUD对象: ```python crud_your_model = CRUDYourModel(YourModel) ``` ### 基础操作示例 ```python # 创建记录 new_item = crud_your_model.create(db, obj_in=item_create_schema) # 获取单条记录 item = crud_your_model.get(db, id=123) # 获取多条记录 items = crud_your_model.get_multi(db, skip=0, limit=100) # 更新记录 updated_item = crud_your_model.update(db, db_obj=existing_item, obj_in=item_update_schema) # 删除记录 crud_your_model.remove(db, id=123) ``` ### 自定义方法示例 ```python class CRUDYourModel(CRUDBase[YourModel, YourCreateSchema, YourUpdateSchema]): def get_by_custom_field(self, db: Session, field_value: str) -> Optional[YourModel]: return db.query(self.model).filter(self.model.custom_field == field_value).first() ``` ### 注意事项 1. CRUDBase需要三个类型参数: - ModelType: SQLAlchemy模型类 - CreateSchemaType: Pydantic创建模型 - UpdateSchemaType: Pydantic更新模型 2. 所有方法都需要传入数据库会话(db: Session)参数 3. 更新操作支持两种方式: - 字典形式:`update(db, db_obj=item, obj_in={"field": "new_value"})` - Pydantic模型:`update(db, db_obj=item, obj_in=ItemUpdate(field="new_value"))` ## API文档 启动服务后访问: http://localhost:2333/docs