2024-12-31 22:27:04 +08:00
|
|
|
|
# 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
|
|
|
|
|
```
|
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
## 数据库管理
|
2024-12-31 22:27:04 +08:00
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
### 添加新的数据库表
|
2024-12-31 22:27:04 +08:00
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
1. 创建模型文件:
|
2024-12-31 22:27:04 +08:00
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
将同类型的表模型放在同一个文件中。文件命名规则:去除表名的 `ims_` 前缀,例如:
|
|
|
|
|
- `ims_account_wechats`、`ims_account_wxapp` 等表 → `account.py`
|
|
|
|
|
- `ims_uni_account`、`ims_uni_settings` 等表 → `uni_account.py`
|
2024-12-31 22:27:04 +08:00
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
```python
|
|
|
|
|
# filepath: mooc/models/account.py
|
2024-12-31 22:27:04 +08:00
|
|
|
|
from sqlalchemy import Column, Integer, String, SmallInteger
|
|
|
|
|
from mooc.db.database import Base
|
2025-01-04 01:13:47 +08:00
|
|
|
|
|
2024-12-31 22:27:04 +08:00
|
|
|
|
class AccountWechats(Base):
|
2025-01-04 01:13:47 +08:00
|
|
|
|
"""微信公众号账号表"""
|
2024-12-31 22:27:04 +08:00
|
|
|
|
__tablename__ = "ims_account_wechats"
|
2025-01-04 01:13:47 +08:00
|
|
|
|
|
2024-12-31 22:27:04 +08:00
|
|
|
|
acid = Column(Integer, primary_key=True)
|
|
|
|
|
uniacid = Column(Integer, nullable=False)
|
2025-01-04 01:13:47 +08:00
|
|
|
|
# ... 其他字段
|
|
|
|
|
```
|
2024-12-31 22:27:04 +08:00
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
2. 在 `mooc/models/__init__.py` 中注册表:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# 添加到 expected_tables 集合中
|
|
|
|
|
expected_tables = {
|
|
|
|
|
# ... 现有表 ...
|
|
|
|
|
'ims_account_wechats', # 新添加的表
|
|
|
|
|
}
|
2024-12-31 22:27:04 +08:00
|
|
|
|
```
|
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
3. 导出模型类:
|
|
|
|
|
|
2024-12-31 22:27:04 +08:00
|
|
|
|
```python
|
2025-01-04 01:13:47 +08:00
|
|
|
|
# 在 mooc/models/__init__.py 中添加导出
|
|
|
|
|
from mooc.models.account import AccountWechats
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
4. 创建 Schema:
|
2024-12-31 22:27:04 +08:00
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
```python
|
|
|
|
|
# filepath: mooc/schemas/account.py
|
2024-12-31 22:27:04 +08:00
|
|
|
|
from pydantic import BaseModel
|
|
|
|
|
|
|
|
|
|
class AccountWechatsBase(BaseModel):
|
2025-01-04 01:13:47 +08:00
|
|
|
|
uniacid: int
|
|
|
|
|
# ... 其他字段
|
2024-12-31 22:27:04 +08:00
|
|
|
|
|
|
|
|
|
class AccountWechatsCreate(AccountWechatsBase):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
class AccountWechatsUpdate(BaseModel):
|
2025-01-04 01:13:47 +08:00
|
|
|
|
# 可选字段用于更新
|
|
|
|
|
uniacid: Optional[int] = None
|
2024-12-31 22:27:04 +08:00
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
class AccountWechatsRead(AccountWechatsBase):
|
|
|
|
|
acid: int
|
|
|
|
|
|
2024-12-31 22:27:04 +08:00
|
|
|
|
class Config:
|
2025-01-04 01:13:47 +08:00
|
|
|
|
from_attributes = True
|
2024-12-31 22:27:04 +08:00
|
|
|
|
```
|
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
5. 创建 CRUD 操作:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# filepath: mooc/crud/crud_account.py
|
2025-01-03 18:10:40 +08:00
|
|
|
|
from mooc.crud.crud_base import CRUDBase
|
2024-12-31 22:27:04 +08:00
|
|
|
|
|
2025-01-03 18:10:40 +08:00
|
|
|
|
class CRUDAccountWechats(CRUDBase[AccountWechats, AccountWechatsCreate, AccountWechatsUpdate]):
|
|
|
|
|
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountWechats]:
|
2025-01-04 01:13:47 +08:00
|
|
|
|
return self.get_by_field(db, "uniacid", uniacid)
|
2024-12-31 22:27:04 +08:00
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
# 创建实例
|
|
|
|
|
account_wechats = CRUDAccountWechats(AccountWechats)
|
2024-12-31 22:27:04 +08:00
|
|
|
|
```
|
2025-01-03 18:10:40 +08:00
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
6. 添加 API 路由:
|
|
|
|
|
|
2024-12-31 22:27:04 +08:00
|
|
|
|
```python
|
2025-01-04 01:13:47 +08:00
|
|
|
|
# filepath: mooc/api/v1/endpoints/account.py
|
|
|
|
|
@account_router.post("/wechats", response_model=AccountWechatsRead)
|
|
|
|
|
def create_wechat_account(
|
|
|
|
|
*,
|
|
|
|
|
db: Session = Depends(deps.get_db),
|
|
|
|
|
account_in: AccountWechatsCreate,
|
|
|
|
|
):
|
|
|
|
|
"""创建微信公众号账号"""
|
|
|
|
|
return account_wechats.create(db=db, obj_in=account_in)
|
2024-12-31 22:27:04 +08:00
|
|
|
|
```
|
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
### 数据库表自动创建
|
|
|
|
|
|
|
|
|
|
应用启动时会自动执行以下操作:
|
|
|
|
|
1. 导入并验证所有模型定义
|
|
|
|
|
2. 检查数据库中缺失的表
|
|
|
|
|
3. 自动创建缺失的表
|
|
|
|
|
|
|
|
|
|
你可以通过查看应用日志了解表创建的详细情况:
|
2024-12-31 22:27:04 +08:00
|
|
|
|
```bash
|
|
|
|
|
python main.py
|
|
|
|
|
```
|
|
|
|
|
|
2025-01-04 01:13:47 +08:00
|
|
|
|
### 注意事项
|
|
|
|
|
|
|
|
|
|
1. 模型类名采用帕斯卡命名法(PascalCase),去除 `ims_` 前缀
|
|
|
|
|
2. 表名(`__tablename__`)必须与数据库中的实际表名完全一致
|
|
|
|
|
3. 字段类型要与数据库定义严格匹配
|
|
|
|
|
4. 确保主键和索引的正确定义
|
|
|
|
|
5. 添加适当的文档字符串说明表的用途
|
|
|
|
|
|
|
|
|
|
### 调试帮助
|
|
|
|
|
|
|
|
|
|
如果遇到问题,可以:
|
|
|
|
|
1. 检查日志输出了解具体错误
|
|
|
|
|
2. 使用 `get_all_table_names()` 查看已注册的表
|
|
|
|
|
3. 验证模型定义是否完整
|
|
|
|
|
4. 确认数据库连接配置是否正确
|
|
|
|
|
|
2025-01-03 18:03:30 +08:00
|
|
|
|
## 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"))`
|
|
|
|
|
|
2024-12-31 22:27:04 +08:00
|
|
|
|
## API文档
|
|
|
|
|
|
|
|
|
|
启动服务后访问: http://localhost:2333/docs
|
2025-01-04 01:13:47 +08:00
|
|
|
|
|
|
|
|
|
### 使用 AI 生成模型代码
|
|
|
|
|
|
|
|
|
|
当你有一个新的数据库表需要添加时,可以使用以下方式让 AI 帮助生成代码:
|
|
|
|
|
|
|
|
|
|
1. 准备 SQL 建表语句,例如:
|
|
|
|
|
```sql
|
|
|
|
|
CREATE TABLE `ims_uni_settings` (
|
|
|
|
|
`uniacid` int(10) UNSIGNED NOT NULL,
|
|
|
|
|
`passport` varchar(200) NOT NULL,
|
|
|
|
|
`oauth` varchar(100) NOT NULL,
|
|
|
|
|
-- ... 其他字段
|
|
|
|
|
PRIMARY KEY (`uniacid`)
|
|
|
|
|
) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. 使用以下提示词模板:
|
|
|
|
|
```
|
|
|
|
|
请帮我为这个表生成 FastAPI + SQLAlchemy 的实现,包括:
|
|
|
|
|
1. SQLAlchemy 模型(models/xxx.py)
|
|
|
|
|
2. Pydantic Schema(schemas/xxx.py)
|
|
|
|
|
3. CRUD 操作(crud/crud_xxx.py)
|
|
|
|
|
4. API 路由(api/v1/endpoints/xxx.py)
|
|
|
|
|
|
|
|
|
|
要求:
|
|
|
|
|
- 遵循项目的命名规范(去除ims_前缀,使用帕斯卡命名法)
|
|
|
|
|
- 确保字段类型映射正确
|
|
|
|
|
- 包含必要的文档注释
|
|
|
|
|
- 实现基本的 CRUD 操作和常用查询方法
|
|
|
|
|
|
|
|
|
|
[SQL建表语句]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. 对生成的代码进行以下检查:
|
|
|
|
|
- 表名是否与数据库一致
|
|
|
|
|
- 字段类型是否正确映射
|
|
|
|
|
- 主键和索引是否正确定义
|
|
|
|
|
- 是否符合项目的命名规范
|
|
|
|
|
- CRUD 方法是否满足业务需求
|
|
|
|
|
|
|
|
|
|
4. 常用的 SQL 类型映射参考:
|
|
|
|
|
```python
|
|
|
|
|
# MySQL 到 SQLAlchemy 的类型映射
|
|
|
|
|
int/bigint -> Integer
|
|
|
|
|
varchar/char -> String(length)
|
|
|
|
|
text -> Text
|
|
|
|
|
datetime -> DateTime
|
|
|
|
|
timestamp -> TIMESTAMP
|
|
|
|
|
tinyint -> SmallInteger
|
|
|
|
|
decimal -> DECIMAL(precision, scale)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
5. 示例提示词:
|
|
|
|
|
```
|
|
|
|
|
我需要为以下数据表生成 FastAPI 实现:
|
|
|
|
|
- 表名:ims_uni_settings
|
|
|
|
|
- 主键:uniacid
|
|
|
|
|
- 特殊需求:
|
|
|
|
|
* 需要通过 uniacid 查询的方法
|
|
|
|
|
* 需要处理 Text 类型的 payment 字段
|
|
|
|
|
* 所有字符串字段都是必填的
|
|
|
|
|
|
|
|
|
|
[SQL语句]
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
请生成完整的代码实现。
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
6. 代码生成后的集成步骤:
|
|
|
|
|
- 将模型类添加到对应的 models 文件
|
|
|
|
|
- 在 models/__init__.py 中注册表名
|
|
|
|
|
- 在 api.py 中注册新的路由
|
|
|
|
|
- 检查并测试生成的 API 端点
|
|
|
|
|
|
|
|
|
|
这种方式可以:
|
|
|
|
|
- 快速生成符合项目规范的代码
|
|
|
|
|
- 确保类型映射的准确性
|
|
|
|
|
- 保持代码结构的一致性
|
|
|
|
|
- 减少手动编码的错误
|
2025-01-15 21:03:36 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## PHP 到 FastAPI 迁移指南
|
|
|
|
|
|
|
|
|
|
### 全局变量对应关系
|
|
|
|
|
|
|
|
|
|
1. `$_W` (WeEngine全局配置):
|
2025-01-15 21:18:50 +08:00
|
|
|
|
```php
|
|
|
|
|
$_W = array(
|
|
|
|
|
'config' => array(), // 系统配置信息
|
|
|
|
|
'timestamp' => time(), // 当前时间戳
|
|
|
|
|
'charset' => 'utf8', // 字符集
|
|
|
|
|
'clientip' => '', // 客户端IP
|
|
|
|
|
'uniacid' => 0, // 当前统一公众号ID
|
|
|
|
|
'acid' => 0, // 当前账号ID
|
|
|
|
|
'uid' => 0, // 当前用户ID
|
|
|
|
|
'isajax' => false, // 是否AJAX请求
|
|
|
|
|
'ispost' => false, // 是否POST请求
|
|
|
|
|
'siteroot' => '', // 站点根目录URL
|
|
|
|
|
'siteurl' => '', // 当前URL
|
|
|
|
|
'attachurl' => '', // 附件URL
|
|
|
|
|
'setting' => array(), // 站点设置
|
|
|
|
|
'module' => array() // 当前模块信息
|
|
|
|
|
);
|
2025-01-15 21:03:36 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. `$_GPC` (全局请求参数):
|
2025-01-15 21:18:50 +08:00
|
|
|
|
```php
|
|
|
|
|
$_GPC = array_merge(
|
|
|
|
|
$_GET, // GET参数
|
|
|
|
|
$_POST, // POST参数
|
|
|
|
|
$_COOKIE // COOKIE数据
|
|
|
|
|
);
|
2025-01-15 21:03:36 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 迁移方法步骤
|
|
|
|
|
|
|
|
|
|
以迁移 `dopageLogin` 为例:
|
|
|
|
|
|
|
|
|
|
1. 在 `wxapp.py` 中添加路由:
|
|
|
|
|
```python
|
|
|
|
|
@wxapp_router.post("/index")
|
|
|
|
|
async def handle_wxapp_request(
|
|
|
|
|
request: Request,
|
|
|
|
|
i: str, # uniacid
|
|
|
|
|
do: Optional[str] = None,
|
|
|
|
|
db: Session = Depends(get_db)
|
|
|
|
|
):
|
|
|
|
|
# 处理不同的 do 参数
|
|
|
|
|
if do == "Login":
|
|
|
|
|
return await handle_login(request, i, db)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. 创建请求数据模型:
|
|
|
|
|
```python
|
|
|
|
|
class LoginRequest(BaseModel):
|
|
|
|
|
code: str
|
|
|
|
|
encryptedData: Optional[str] = None
|
|
|
|
|
iv: Optional[str] = None
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. 创建处理函数:
|
|
|
|
|
```python
|
|
|
|
|
async def handle_login(request: Request, uniacid: str, db: Session):
|
|
|
|
|
# 获取所有参数
|
|
|
|
|
params = await get_all_params(request)
|
|
|
|
|
|
|
|
|
|
# 验证必要参数
|
|
|
|
|
if not params.get("code"):
|
|
|
|
|
return {"code": 1, "msg": "code值获取失败"}
|
|
|
|
|
|
|
|
|
|
# 获取小程序配置
|
|
|
|
|
account = await get_account_info(db, uniacid)
|
|
|
|
|
|
|
|
|
|
# 业务逻辑处理
|
|
|
|
|
try:
|
|
|
|
|
result = await process_login(
|
|
|
|
|
db,
|
|
|
|
|
code=params["code"],
|
|
|
|
|
appid=account.key,
|
|
|
|
|
secret=account.secret,
|
|
|
|
|
encrypted_data=params.get("encryptedData"),
|
|
|
|
|
iv=params.get("iv")
|
|
|
|
|
)
|
|
|
|
|
return {"code": 0, "msg": "登录成功", "data": result}
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return {"code": 1, "msg": str(e)}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
4. 实现数据库操作:
|
|
|
|
|
```python
|
|
|
|
|
# 在 crud/crud_goouc_fullexam_user.py 中
|
|
|
|
|
class CRUDUser(CRUDBase[User, UserCreate, UserUpdate]):
|
|
|
|
|
async def get_by_openid(self, db: Session, *, openid: str) -> Optional[User]:
|
|
|
|
|
return db.query(self.model).filter(
|
|
|
|
|
self.model.openid == openid,
|
|
|
|
|
self.model.istatus == 1
|
|
|
|
|
).first()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
5. 实现业务逻辑:
|
|
|
|
|
```python
|
|
|
|
|
# 在 services/user.py 中
|
|
|
|
|
async def process_login(
|
|
|
|
|
db: Session,
|
|
|
|
|
code: str,
|
|
|
|
|
appid: str,
|
|
|
|
|
secret: str,
|
|
|
|
|
encrypted_data: Optional[str] = None,
|
|
|
|
|
iv: Optional[str] = None
|
|
|
|
|
) -> Dict:
|
|
|
|
|
# 1. 调用微信API获取session_key和openid
|
|
|
|
|
# 2. 解密用户信息
|
|
|
|
|
# 3. 查找或创建用户
|
|
|
|
|
# 4. 更新登录时间
|
|
|
|
|
# 5. 返回结果
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 注意事项
|
|
|
|
|
|
|
|
|
|
1. 参数获取:
|
|
|
|
|
- PHP: `$_GPC["param"]`
|
|
|
|
|
- FastAPI: `params = await get_all_params(request)`
|
|
|
|
|
|
|
|
|
|
2. 数据库操作:
|
|
|
|
|
- PHP: `pdo_fetch("SELECT * FROM " . tablename($this->t_user))`
|
|
|
|
|
- FastAPI: `db.query(User).filter(User.id == uid).first()`
|
|
|
|
|
|
|
|
|
|
3. 返回格式:
|
|
|
|
|
- PHP: `$this->result(0, "success", $data)`
|
|
|
|
|
- FastAPI: `{"code": 0, "msg": "success", "data": data}`
|
|
|
|
|
|
|
|
|
|
4. 错误处理:
|
|
|
|
|
```python
|
|
|
|
|
try:
|
|
|
|
|
# 业务逻辑
|
|
|
|
|
return {"code": 0, "msg": "success", "data": result}
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return {"code": 1, "msg": str(e)}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
5. 表名处理:
|
|
|
|
|
- PHP: `tablename($this->t_user)`
|
|
|
|
|
- FastAPI: 在模型定义中指定 `__tablename__ = "ims_goouc_fullexam_user"`
|