优化数据库表的创建与检查

This commit is contained in:
?..濡.. 2025-01-04 01:13:47 +08:00
parent ecf90fec31
commit 173580c0af
12 changed files with 1677 additions and 199 deletions

286
README.md
View File

@ -76,178 +76,127 @@ alembic revision --autogenerate -m "Initial migration"
alembic upgrade head alembic upgrade head
``` ```
## 添加数据库表 ## 数据库管理
### 1.创建模型文件: ### 添加新的数据库表
**因为表格太多可以把同类型表放在同一个文件文件命名规则ims_account_wechats、ims_account_wxapp、ims_account_xzapp等表格去除前缀和后缀即为account.py** 1. 创建模型文件:
将同类型的表模型放在同一个文件中。文件命名规则:去除表名的 `ims_` 前缀,例如:
- `ims_account_wechats`、`ims_account_wxapp` 等表 → `account.py`
- `ims_uni_account`、`ims_uni_settings` 等表 → `uni_account.py`
```python ```python
# 这个模型类AccountWechats用于映射ims_account_wechats表 # filepath: mooc/models/account.py
# 1. 在ORM层中代表数据库表结构方便CRUD操作。
# 2. 在FastAPI中引用该模型时可以使用Pydantic自动转换ORM对象到响应模型。
# 3. 创建模型时需确保表名(__tablename__)与真实的数据库表名保持一致,否则查询和插入可能失败。
# 4. 字段类型要与数据库中定义的列类型严格匹配,避免出现不兼容或异常。
# 5. 通过Primary Keyacid唯一标识记录确保ORM能正确追踪和更新该对象。
# 6. config.orm_mode = True允许直接把SQLAlchemy模型实例转换为Pydantic模型对象。
# filepath: ExamService/mooc/models/account.py
from sqlalchemy import Column, Integer, String, SmallInteger from sqlalchemy import Column, Integer, String, SmallInteger
from mooc.db.database import Base from mooc.db.database import Base
# 类名命名规则: 去除ims前缀后采用 帕斯卡命名法,无连接符每个单词手写大写
# AccountWechats模型用于映射数据库表 ims_account_wechats
class AccountWechats(Base): class AccountWechats(Base):
"""微信公众号账号表"""
__tablename__ = "ims_account_wechats" __tablename__ = "ims_account_wechats"
acid = Column(Integer, primary_key=True) acid = Column(Integer, primary_key=True)
uniacid = Column(Integer, nullable=False) 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: 2. 在 `mooc/models/__init__.py` 中注册表:
```python
# filepath: ExamService/mooc/schemas/account.py
```python
# 添加到 expected_tables 集合中
expected_tables = {
# ... 现有表 ...
'ims_account_wechats', # 新添加的表
}
```
3. 导出模型类:
```python
# 在 mooc/models/__init__.py 中添加导出
from mooc.models.account import AccountWechats
```
4. 创建 Schema:
```python
# filepath: mooc/schemas/account.py
from pydantic import BaseModel from pydantic import BaseModel
from typing import Optional
class AccountWechatsBase(BaseModel): class AccountWechatsBase(BaseModel):
""" uniacid: int
数据模型基类: 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): class AccountWechatsCreate(AccountWechatsBase):
"""
用于创建新微信帐号记录:
- 继承自AccountWechatsBase, 不额外添加字段
- 仅表示此Schema专用于'创建'场景
"""
# 用于创建新记录,包含所有必填字段
pass pass
class AccountWechatsUpdate(BaseModel): class AccountWechatsUpdate(BaseModel):
""" # 可选字段用于更新
用于更新已有微信帐号记录: uniacid: Optional[int] = None
- 只包含可选字段,未在此处的内容将保持不变
- 注意: exclude_unset=True 可以避免更新空值
"""
token: Optional[str] # 可选更新token
encodingaeskey: Optional[str]# 可选更新AES key
class AccountWechats(AccountWechatsBase): class AccountWechatsRead(AccountWechatsBase):
""" acid: int
表示完整的微信帐号记录:
- acid: 数据库主键ID
- 包含所有字段的最终模型ORM转换时使用
"""
acid: int # 表中的主键ID
class Config: class Config:
from_attributes = True # 允许与ORM对象进行直接转换 from_attributes = True
``` ```
### 3.创建 CRUD: 5. 创建 CRUD 操作:
```python ```python
# filepath: ExamService/mooc/crud/crud_account.py # filepath: mooc/crud/crud_account.py
from typing import Optional
from sqlalchemy.orm import Session
from mooc.crud.crud_base import CRUDBase 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]): class CRUDAccountWechats(CRUDBase[AccountWechats, AccountWechatsCreate, AccountWechatsUpdate]):
"""
AccountWechats的CRUD操作类
继承自CRUDBase基类实现基础的增删改查功能
可以根据需要添加自定义的查询方法
"""
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountWechats]: def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountWechats]:
""" return self.get_by_field(db, "uniacid", uniacid)
根据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) 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.注册模型: 6. 添加 API 路由:
```python ```python
# filepath: ExamService/mooc/db/base.py # filepath: mooc/api/v1/endpoints/account.py
from mooc.db.database import Base @account_router.post("/wechats", response_model=AccountWechatsRead)
from mooc.models.admin import Admin, Account, AccountWebapp def create_wechat_account(
from mooc.models.account import AccountWechats # 新增,将创建好的模型类导入即可 *,
db: Session = Depends(deps.get_db),
account_in: AccountWechatsCreate,
):
"""创建微信公众号账号"""
return account_wechats.create(db=db, obj_in=account_in)
``` ```
### 5.运行代码更新数据库信息 ### 数据库表自动创建
应用启动时会自动执行以下操作:
1. 导入并验证所有模型定义
2. 检查数据库中缺失的表
3. 自动创建缺失的表
你可以通过查看应用日志了解表创建的详细情况:
```bash ```bash
python main.py python main.py
``` ```
### 注意事项
1. 模型类名采用帕斯卡命名法PascalCase去除 `ims_` 前缀
2. 表名(`__tablename__`)必须与数据库中的实际表名完全一致
3. 字段类型要与数据库定义严格匹配
4. 确保主键和索引的正确定义
5. 添加适当的文档字符串说明表的用途
### 调试帮助
如果遇到问题,可以:
1. 检查日志输出了解具体错误
2. 使用 `get_all_table_names()` 查看已注册的表
3. 验证模型定义是否完整
4. 确认数据库连接配置是否正确
## CRUDBase 使用指南 ## CRUDBase 使用指南
### 简介 ### 简介
@ -316,3 +265,82 @@ class CRUDYourModel(CRUDBase[YourModel, YourCreateSchema, YourUpdateSchema]):
## API文档 ## API文档
启动服务后访问: http://localhost:2333/docs 启动服务后访问: http://localhost:2333/docs
### 使用 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 Schemaschemas/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 端点
这种方式可以:
- 快速生成符合项目规范的代码
- 确保类型映射的准确性
- 保持代码结构的一致性
- 减少手动编码的错误

View File

@ -1,9 +1,8 @@
from fastapi import APIRouter from fastapi import APIRouter
from mooc.api.v1.endpoints import admin, wechat, account from mooc.api.v1.endpoints import admin, wechat, account, uni_account
api_router = APIRouter() api_router = APIRouter()
# עԱ·ɣǰ׺Ϊ/admins
api_router.include_router( api_router.include_router(
admin.admin_router, admin.admin_router,
prefix="/admins", prefix="/admins",
@ -25,3 +24,11 @@ api_router.include_router(
# Add WeChat endpoints # Add WeChat endpoints
api_router.include_router(wechat.router, prefix="/wechat", tags=["wechat"]) api_router.include_router(wechat.router, prefix="/wechat", tags=["wechat"])
api_router.include_router(
uni_account.uni_account_router,
prefix="/uni-accounts",
tags=["uni-accounts"]
)

View File

@ -0,0 +1,682 @@
from typing import List
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from mooc.api import deps
from mooc.crud.crud_uni_account import (
uni_account, uni_account_extra_modules,
uni_account_group, uni_account_menus,
uni_account_modules, uni_account_modules_shortcut,
uni_account_users, uni_group,
uni_link_uniacid, uni_modules,
uni_verifycode, uni_settings
)
from mooc.schemas.uni_account import (
UniAccountCreate,
UniAccountRead,
UniAccountUpdate,
UniAccountExtraModulesCreate,
UniAccountExtraModulesRead,
UniAccountExtraModulesUpdate,
UniAccountGroupCreate,
UniAccountGroupRead,
UniAccountGroupUpdate,
UniAccountMenusCreate,
UniAccountMenusRead,
UniAccountMenusUpdate,
UniAccountModulesCreate,
UniAccountModulesRead,
UniAccountModulesUpdate,
UniAccountModulesShortcutCreate,
UniAccountModulesShortcutRead,
UniAccountModulesShortcutUpdate,
UniAccountUsersCreate,
UniAccountUsersRead,
UniAccountUsersUpdate,
UniGroupCreate,
UniGroupRead,
UniGroupUpdate,
UniLinkUniacidCreate,
UniLinkUniacidRead,
UniLinkUniacidUpdate,
UniModulesCreate,
UniModulesRead,
UniModulesUpdate,
UniVerifycodeCreate,
UniVerifycodeRead,
UniVerifycodeUpdate,
UniSettingsCreate,
UniSettingsRead,
UniSettingsUpdate
)
uni_account_router = APIRouter()
# UniAccount 路由
@uni_account_router.post("/", response_model=UniAccountRead)
def create_uni_account(
*,
db: Session = Depends(deps.get_db),
uni_account_in: UniAccountCreate,
):
"""
创建统一公众号账户
"""
return uni_account.create(db=db, obj_in=uni_account_in)
@uni_account_router.get("/{uniacid}", response_model=UniAccountRead)
def read_uni_account(
*,
db: Session = Depends(deps.get_db),
uniacid: int,
):
"""
获取统一公众号账户信息
"""
db_uni_account = uni_account.get(db=db, id=uniacid)
if not db_uni_account:
raise HTTPException(
status_code=404,
detail="UniAccount not found"
)
return db_uni_account
@uni_account_router.put("/{uniacid}", response_model=UniAccountRead)
def update_uni_account(
*,
db: Session = Depends(deps.get_db),
uniacid: int,
uni_account_in: UniAccountUpdate,
):
"""
更新统一公众号账户信息
"""
db_uni_account = uni_account.get(db=db, id=uniacid)
if not db_uni_account:
raise HTTPException(
status_code=404,
detail="UniAccount not found"
)
return uni_account.update(db=db, db_obj=db_uni_account, obj_in=uni_account_in)
@uni_account_router.delete("/{uniacid}", response_model=UniAccountRead)
def delete_uni_account(
*,
db: Session = Depends(deps.get_db),
uniacid: int,
):
"""
删除统一公众号账户
"""
db_uni_account = uni_account.get(db=db, id=uniacid)
if not db_uni_account:
raise HTTPException(
status_code=404,
detail="UniAccount not found"
)
return uni_account.delete(db=db, id=uniacid)
# UniAccountExtraModules 路由
@uni_account_router.post("/modules", response_model=UniAccountExtraModulesRead)
def create_extra_modules(
*,
db: Session = Depends(deps.get_db),
modules_in: UniAccountExtraModulesCreate,
):
"""
创建账户额外模块
"""
return uni_account_extra_modules.create(db=db, obj_in=modules_in)
@uni_account_router.get("/modules/{id}", response_model=UniAccountExtraModulesRead)
def read_extra_modules(
*,
db: Session = Depends(deps.get_db),
id: int,
):
"""
获取账户额外模块信息
"""
db_modules = uni_account_extra_modules.get(db=db, id=id)
if not db_modules:
raise HTTPException(
status_code=404,
detail="Extra modules not found"
)
return db_modules
@uni_account_router.get("/modules/by-uniacid/{uniacid}", response_model=UniAccountExtraModulesRead)
def read_extra_modules_by_uniacid(
*,
db: Session = Depends(deps.get_db),
uniacid: int,
):
"""
通过uniacid获取账户额外模块信息
"""
db_modules = uni_account_extra_modules.get_by_uniacid(db=db, uniacid=uniacid)
if not db_modules:
raise HTTPException(
status_code=404,
detail="Extra modules not found"
)
return db_modules
@uni_account_router.put("/modules/{id}", response_model=UniAccountExtraModulesRead)
def update_extra_modules(
*,
db: Session = Depends(deps.get_db),
id: int,
modules_in: UniAccountExtraModulesUpdate,
):
"""
更新账户额外模块信息
"""
db_modules = uni_account_extra_modules.get(db=db, id=id)
if not db_modules:
raise HTTPException(
status_code=404,
detail="Extra modules not found"
)
return uni_account_extra_modules.update(db=db, db_obj=db_modules, obj_in=modules_in)
@uni_account_router.delete("/modules/{id}", response_model=UniAccountExtraModulesRead)
def delete_extra_modules(
*,
db: Session = Depends(deps.get_db),
id: int,
):
"""
删除账户额外模块
"""
db_modules = uni_account_extra_modules.get(db=db, id=id)
if not db_modules:
raise HTTPException(
status_code=404,
detail="Extra modules not found"
)
return uni_account_extra_modules.delete(db=db, id=id)
# UniAccountGroup 路由
@uni_account_router.post("/groups", response_model=UniAccountGroupRead)
def create_group(
*,
db: Session = Depends(deps.get_db),
group_in: UniAccountGroupCreate,
):
"""创建账户组关联"""
return uni_account_group.create(db=db, obj_in=group_in)
@uni_account_router.get("/groups/{id}", response_model=UniAccountGroupRead)
def read_group(*, db: Session = Depends(deps.get_db), id: int):
"""获取账户组关联信息"""
group = uni_account_group.get(db=db, id=id)
if not group:
raise HTTPException(status_code=404, detail="Account group not found")
return group
@uni_account_router.put("/groups/{id}", response_model=UniAccountGroupRead)
def update_group(
*,
db: Session = Depends(deps.get_db),
id: int,
group_in: UniAccountGroupUpdate,
):
"""更新账户组关联信息"""
group = uni_account_group.get(db=db, id=id)
if not group:
raise HTTPException(status_code=404, detail="Account group not found")
return uni_account_group.update(db=db, db_obj=group, obj_in=group_in)
@uni_account_router.delete("/groups/{id}", response_model=UniAccountGroupRead)
def delete_group(*, db: Session = Depends(deps.get_db), id: int):
"""删除账户组关联"""
group = uni_account_group.get(db=db, id=id)
if not group:
raise HTTPException(status_code=404, detail="Account group not found")
return uni_account_group.delete(db=db, id=id)
# UniAccountMenus 路由
@uni_account_router.post("/menus", response_model=UniAccountMenusRead)
def create_menu(
*,
db: Session = Depends(deps.get_db),
menu_in: UniAccountMenusCreate,
):
"""创建账户菜单"""
return uni_account_menus.create(db=db, obj_in=menu_in)
@uni_account_router.get("/menus/{id}", response_model=UniAccountMenusRead)
def read_menu(*, db: Session = Depends(deps.get_db), id: int):
"""获取账户菜单信息"""
menu = uni_account_menus.get(db=db, id=id)
if not menu:
raise HTTPException(status_code=404, detail="Account menu not found")
return menu
@uni_account_router.get("/menus/by-uniacid/{uniacid}", response_model=UniAccountMenusRead)
def read_menu_by_uniacid(*, db: Session = Depends(deps.get_db), uniacid: int):
"""通过uniacid获取账户菜单信息"""
menu = uni_account_menus.get_by_uniacid(db=db, uniacid=uniacid)
if not menu:
raise HTTPException(status_code=404, detail="Account menu not found")
return menu
@uni_account_router.put("/menus/{id}", response_model=UniAccountMenusRead)
def update_menu(
*,
db: Session = Depends(deps.get_db),
id: int,
menu_in: UniAccountMenusUpdate,
):
"""更新账户菜单信息"""
menu = uni_account_menus.get(db=db, id=id)
if not menu:
raise HTTPException(status_code=404, detail="Account menu not found")
return uni_account_menus.update(db=db, db_obj=menu, obj_in=menu_in)
@uni_account_router.delete("/menus/{id}", response_model=UniAccountMenusRead)
def delete_menu(*, db: Session = Depends(deps.get_db), id: int):
"""删除账户菜单"""
menu = uni_account_menus.get(db=db, id=id)
if not menu:
raise HTTPException(status_code=404, detail="Account menu not found")
return uni_account_menus.delete(db=db, id=id)
# UniAccountModules 路由
@uni_account_router.post("/modules", response_model=UniAccountModulesRead)
def create_module(
*,
db: Session = Depends(deps.get_db),
module_in: UniAccountModulesCreate,
):
"""创建账户模块"""
return uni_account_modules.create(db=db, obj_in=module_in)
@uni_account_router.get("/modules/{id}", response_model=UniAccountModulesRead)
def read_module(*, db: Session = Depends(deps.get_db), id: int):
"""获取账户模块信息"""
module = uni_account_modules.get(db=db, id=id)
if not module:
raise HTTPException(status_code=404, detail="Account module not found")
return module
@uni_account_router.get("/modules/by-uniacid/{uniacid}", response_model=UniAccountModulesRead)
def read_module_by_uniacid(*, db: Session = Depends(deps.get_db), uniacid: int):
"""通过uniacid获取账户模块信息"""
module = uni_account_modules.get_by_uniacid(db=db, uniacid=uniacid)
if not module:
raise HTTPException(status_code=404, detail="Account module not found")
return module
@uni_account_router.put("/modules/{id}", response_model=UniAccountModulesRead)
def update_module(
*,
db: Session = Depends(deps.get_db),
id: int,
module_in: UniAccountModulesUpdate,
):
"""更新账户模块信息"""
module = uni_account_modules.get(db=db, id=id)
if not module:
raise HTTPException(status_code=404, detail="Account module not found")
return uni_account_modules.update(db=db, db_obj=module, obj_in=module_in)
@uni_account_router.delete("/modules/{id}", response_model=UniAccountModulesRead)
def delete_module(*, db: Session = Depends(deps.get_db), id: int):
"""删除账户模块"""
module = uni_account_modules.get(db=db, id=id)
if not module:
raise HTTPException(status_code=404, detail="Account module not found")
return uni_account_modules.delete(db=db, id=id)
# UniAccountModulesShortcut 完整路由
@uni_account_router.post("/modules-shortcut", response_model=UniAccountModulesShortcutRead)
def create_module_shortcut(
*,
db: Session = Depends(deps.get_db),
shortcut_in: UniAccountModulesShortcutCreate,
):
"""创建模块快捷方式"""
return uni_account_modules_shortcut.create(db=db, obj_in=shortcut_in)
@uni_account_router.get("/modules-shortcut/{id}", response_model=UniAccountModulesShortcutRead)
def read_module_shortcut(*, db: Session = Depends(deps.get_db), id: int):
"""获取模块快捷方式"""
shortcut = uni_account_modules_shortcut.get(db=db, id=id)
if not shortcut:
raise HTTPException(status_code=404, detail="Module shortcut not found")
return shortcut
@uni_account_router.get("/modules-shortcut/by-uniacid/{uniacid}", response_model=UniAccountModulesShortcutRead)
def read_module_shortcut_by_uniacid(*, db: Session = Depends(deps.get_db), uniacid: int):
"""通过uniacid获取模块快捷方式"""
shortcut = uni_account_modules_shortcut.get_by_uniacid(db=db, uniacid=uniacid)
if not shortcut:
raise HTTPException(status_code=404, detail="Module shortcut not found")
return shortcut
@uni_account_router.put("/modules-shortcut/{id}", response_model=UniAccountModulesShortcutRead)
def update_module_shortcut(
*,
db: Session = Depends(deps.get_db),
id: int,
shortcut_in: UniAccountModulesShortcutUpdate,
):
"""更新模块快捷方式"""
shortcut = uni_account_modules_shortcut.get(db=db, id=id)
if not shortcut:
raise HTTPException(status_code=404, detail="Module shortcut not found")
return uni_account_modules_shortcut.update(db=db, db_obj=shortcut, obj_in=shortcut_in)
@uni_account_router.delete("/modules-shortcut/{id}", response_model=UniAccountModulesShortcutRead)
def delete_module_shortcut(*, db: Session = Depends(deps.get_db), id: int):
"""删除模块快捷方式"""
shortcut = uni_account_modules_shortcut.get(db=db, id=id)
if not shortcut:
raise HTTPException(status_code=404, detail="Module shortcut not found")
return uni_account_modules_shortcut.delete(db=db, id=id)
# UniAccountUsers 完整路由
@uni_account_router.post("/users", response_model=UniAccountUsersRead)
def create_account_user(
*,
db: Session = Depends(deps.get_db),
user_in: UniAccountUsersCreate,
):
"""创建账户用户关联"""
return uni_account_users.create(db=db, obj_in=user_in)
@uni_account_router.get("/users/{id}", response_model=UniAccountUsersRead)
def read_account_user(*, db: Session = Depends(deps.get_db), id: int):
"""获取账户用户关联信息"""
user = uni_account_users.get(db=db, id=id)
if not user:
raise HTTPException(status_code=404, detail="Account user not found")
return user
@uni_account_router.get("/users/by-uniacid/{uniacid}", response_model=UniAccountUsersRead)
def read_account_user_by_uniacid(*, db: Session = Depends(deps.get_db), uniacid: int):
"""通过uniacid获取账户用户关联信息"""
user = uni_account_users.get_by_uniacid(db=db, uniacid=uniacid)
if not user:
raise HTTPException(status_code=404, detail="Account user not found")
return user
@uni_account_router.get("/users/by-uid/{uid}", response_model=UniAccountUsersRead)
def read_account_user_by_uid(*, db: Session = Depends(deps.get_db), uid: int):
"""通过uid获取账户用户关联信息"""
user = uni_account_users.get_by_uid(db=db, uid=uid)
if not user:
raise HTTPException(status_code=404, detail="Account user not found")
return user
@uni_account_router.put("/users/{id}", response_model=UniAccountUsersRead)
def update_account_user(
*,
db: Session = Depends(deps.get_db),
id: int,
user_in: UniAccountUsersUpdate,
):
"""更新账户用户关联信息"""
user = uni_account_users.get(db=db, id=id)
if not user:
raise HTTPException(status_code=404, detail="Account user not found")
return uni_account_users.update(db=db, db_obj=user, obj_in=user_in)
@uni_account_router.delete("/users/{id}", response_model=UniAccountUsersRead)
def delete_account_user(*, db: Session = Depends(deps.get_db), id: int):
"""删除账户用户关联"""
user = uni_account_users.get(db=db, id=id)
if not user:
raise HTTPException(status_code=404, detail="Account user not found")
return uni_account_users.delete(db=db, id=id)
# UniGroup 完整路由
@uni_account_router.post("/groups", response_model=UniGroupRead)
def create_uni_group(
*,
db: Session = Depends(deps.get_db),
group_in: UniGroupCreate,
):
"""创建统一公众号组"""
return uni_group.create(db=db, obj_in=group_in)
@uni_account_router.get("/groups/{id}", response_model=UniGroupRead)
def read_uni_group(*, db: Session = Depends(deps.get_db), id: int):
"""获取统一公众号组信息"""
group = uni_group.get(db=db, id=id)
if not group:
raise HTTPException(status_code=404, detail="Uni group not found")
return group
@uni_account_router.get("/groups/by-uniacid/{uniacid}", response_model=UniGroupRead)
def read_uni_group_by_uniacid(*, db: Session = Depends(deps.get_db), uniacid: int):
"""通过uniacid获取统一公众号组信息"""
group = uni_group.get_by_uniacid(db=db, uniacid=uniacid)
if not group:
raise HTTPException(status_code=404, detail="Uni group not found")
return group
@uni_account_router.get("/groups/by-owner/{owner_uid}", response_model=UniGroupRead)
def read_uni_group_by_owner(*, db: Session = Depends(deps.get_db), owner_uid: int):
"""通过owner_uid获取统一公众号组信息"""
group = uni_group.get_by_owner(db=db, owner_uid=owner_uid)
if not group:
raise HTTPException(status_code=404, detail="Uni group not found")
return group
@uni_account_router.put("/groups/{id}", response_model=UniGroupRead)
def update_uni_group(
*,
db: Session = Depends(deps.get_db),
id: int,
group_in: UniGroupUpdate,
):
"""更新统一公众号组信息"""
group = uni_group.get(db=db, id=id)
if not group:
raise HTTPException(status_code=404, detail="Uni group not found")
return uni_group.update(db=db, db_obj=group, obj_in=group_in)
@uni_account_router.delete("/groups/{id}", response_model=UniGroupRead)
def delete_uni_group(*, db: Session = Depends(deps.get_db), id: int):
"""删除统一公众号组"""
group = uni_group.get(db=db, id=id)
if not group:
raise HTTPException(status_code=404, detail="Uni group not found")
return uni_group.delete(db=db, id=id)
# UniLinkUniacid 路由
@uni_account_router.post("/links", response_model=UniLinkUniacidRead)
def create_link_uniacid(
*,
db: Session = Depends(deps.get_db),
link_in: UniLinkUniacidCreate,
):
"""创建公众号链接关系"""
return uni_link_uniacid.create(db=db, obj_in=link_in)
@uni_account_router.get("/links/{id}", response_model=UniLinkUniacidRead)
def read_link_uniacid(*, db: Session = Depends(deps.get_db), id: int):
"""获取公众号链接关系"""
link = uni_link_uniacid.get(db=db, id=id)
if not link:
raise HTTPException(status_code=404, detail="Link uniacid not found")
return link
@uni_account_router.get("/links/by-uniacid/{uniacid}", response_model=UniLinkUniacidRead)
def read_link_uniacid_by_uniacid(*, db: Session = Depends(deps.get_db), uniacid: int):
"""通过uniacid获取公众号链接关系"""
link = uni_link_uniacid.get_by_uniacid(db=db, uniacid=uniacid)
if not link:
raise HTTPException(status_code=404, detail="Link uniacid not found")
return link
@uni_account_router.put("/links/{id}", response_model=UniLinkUniacidRead)
def update_link_uniacid(
*,
db: Session = Depends(deps.get_db),
id: int,
link_in: UniLinkUniacidUpdate,
):
"""更新公众号链接关系"""
link = uni_link_uniacid.get(db=db, id=id)
if not link:
raise HTTPException(status_code=404, detail="Link uniacid not found")
return uni_link_uniacid.update(db=db, db_obj=link, obj_in=link_in)
@uni_account_router.delete("/links/{id}", response_model=UniLinkUniacidRead)
def delete_link_uniacid(*, db: Session = Depends(deps.get_db), id: int):
"""删除公众号链接关系"""
link = uni_link_uniacid.get(db=db, id=id)
if not link:
raise HTTPException(status_code=404, detail="Link uniacid not found")
return uni_link_uniacid.delete(db=db, id=id)
# UniModules 路由
@uni_account_router.post("/uni-modules", response_model=UniModulesRead)
def create_uni_module(
*,
db: Session = Depends(deps.get_db),
module_in: UniModulesCreate,
):
"""创建统一模块"""
return uni_modules.create(db=db, obj_in=module_in)
@uni_account_router.get("/uni-modules/{id}", response_model=UniModulesRead)
def read_uni_module(*, db: Session = Depends(deps.get_db), id: int):
"""获取统一模块信息"""
module = uni_modules.get(db=db, id=id)
if not module:
raise HTTPException(status_code=404, detail="Uni module not found")
return module
@uni_account_router.get("/uni-modules/by-uniacid/{uniacid}", response_model=UniModulesRead)
def read_uni_module_by_uniacid(*, db: Session = Depends(deps.get_db), uniacid: int):
"""通过uniacid获取统一模块信息"""
module = uni_modules.get_by_uniacid(db=db, uniacid=uniacid)
if not module:
raise HTTPException(status_code=404, detail="Uni module not found")
return module
@uni_account_router.put("/uni-modules/{id}", response_model=UniModulesRead)
def update_uni_module(
*,
db: Session = Depends(deps.get_db),
id: int,
module_in: UniModulesUpdate,
):
"""更新统一模块信息"""
module = uni_modules.get(db=db, id=id)
if not module:
raise HTTPException(status_code=404, detail="Uni module not found")
return uni_modules.update(db=db, db_obj=module, obj_in=module_in)
@uni_account_router.delete("/uni-modules/{id}", response_model=UniModulesRead)
def delete_uni_module(*, db: Session = Depends(deps.get_db), id: int):
"""删除统一模块"""
module = uni_modules.get(db=db, id=id)
if not module:
raise HTTPException(status_code=404, detail="Uni module not found")
return uni_modules.delete(db=db, id=id)
# UniVerifycode 路由
@uni_account_router.post("/verifycodes", response_model=UniVerifycodeRead)
def create_verifycode(
*,
db: Session = Depends(deps.get_db),
verifycode_in: UniVerifycodeCreate,
):
"""创建验证码"""
return uni_verifycode.create(db=db, obj_in=verifycode_in)
@uni_account_router.get("/verifycodes/{id}", response_model=UniVerifycodeRead)
def read_verifycode(*, db: Session = Depends(deps.get_db), id: int):
"""获取验证码信息"""
verifycode = uni_verifycode.get(db=db, id=id)
if not verifycode:
raise HTTPException(status_code=404, detail="Verifycode not found")
return verifycode
@uni_account_router.get("/verifycodes/by-uniacid/{uniacid}", response_model=UniVerifycodeRead)
def read_verifycode_by_uniacid(*, db: Session = Depends(deps.get_db), uniacid: int):
"""通过uniacid获取验证码信息"""
verifycode = uni_verifycode.get_by_uniacid(db=db, uniacid=uniacid)
if not verifycode:
raise HTTPException(status_code=404, detail="Verifycode not found")
return verifycode
@uni_account_router.get("/verifycodes/by-receiver/{receiver}", response_model=UniVerifycodeRead)
def read_verifycode_by_receiver(*, db: Session = Depends(deps.get_db), receiver: str):
"""通过接收者获取验证码信息"""
verifycode = uni_verifycode.get_by_receiver(db=db, receiver=receiver)
if not verifycode:
raise HTTPException(status_code=404, detail="Verifycode not found")
return verifycode
@uni_account_router.put("/verifycodes/{id}", response_model=UniVerifycodeRead)
def update_verifycode(
*,
db: Session = Depends(deps.get_db),
id: int,
verifycode_in: UniVerifycodeUpdate,
):
"""更新验证码信息"""
verifycode = uni_verifycode.get(db=db, id=id)
if not verifycode:
raise HTTPException(status_code=404, detail="Verifycode not found")
return uni_verifycode.update(db=db, db_obj=verifycode, obj_in=verifycode_in)
@uni_account_router.delete("/verifycodes/{id}", response_model=UniVerifycodeRead)
def delete_verifycode(*, db: Session = Depends(deps.get_db), id: int):
"""删除验证码"""
verifycode = uni_verifycode.get(db=db, id=id)
if not verifycode:
raise HTTPException(status_code=404, detail="Verifycode not found")
return uni_verifycode.delete(db=db, id=id)
# UniSettings 路由
@uni_account_router.post("/settings", response_model=UniSettingsRead)
def create_settings(
*,
db: Session = Depends(deps.get_db),
settings_in: UniSettingsCreate,
):
"""创建公众号设置"""
# 检查是否已存在该uniacid的设置
existing_settings = uni_settings.get_by_uniacid(db=db, uniacid=settings_in.uniacid)
if existing_settings:
raise HTTPException(
status_code=400,
detail="Settings for this uniacid already exists"
)
return uni_settings.create_with_uniacid(db=db, obj_in=settings_in)
@uni_account_router.get("/settings/{uniacid}", response_model=UniSettingsRead)
def read_settings(*, db: Session = Depends(deps.get_db), uniacid: int):
"""获取公众号设置"""
settings = uni_settings.get_by_uniacid(db=db, uniacid=uniacid)
if not settings:
raise HTTPException(status_code=404, detail="Settings not found")
return settings
@uni_account_router.put("/settings/{uniacid}", response_model=UniSettingsRead)
def update_settings(
*,
db: Session = Depends(deps.get_db),
uniacid: int,
settings_in: UniSettingsUpdate,
):
"""更新公众号设置"""
settings = uni_settings.get_by_uniacid(db=db, uniacid=uniacid)
if not settings:
raise HTTPException(status_code=404, detail="Settings not found")
return uni_settings.update(db=db, db_obj=settings, obj_in=settings_in)
@uni_account_router.delete("/settings/{uniacid}", response_model=UniSettingsRead)
def delete_settings(*, db: Session = Depends(deps.get_db), uniacid: int):
"""删除公众号设置"""
settings = uni_settings.get_by_uniacid(db=db, uniacid=uniacid)
if not settings:
raise HTTPException(status_code=404, detail="Settings not found")
return uni_settings.delete(db=db, id=uniacid)

View File

@ -19,42 +19,37 @@ from mooc.schemas.account import (
class CRUDAccountWechats(CRUDBase[AccountWechats, AccountWechatsCreate, AccountWechatsUpdate]): class CRUDAccountWechats(CRUDBase[AccountWechats, AccountWechatsCreate, AccountWechatsUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountWechats]: def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountWechats]:
return db.query(self.model).filter(self.model.uniacid == uniacid).first() return self.get_by_field(db, "uniacid", uniacid)
class CRUDAccountAliapp(CRUDBase[AccountAliapp, AccountAliappCreate, AccountAliappUpdate]): class CRUDAccountAliapp(CRUDBase[AccountAliapp, AccountAliappCreate, AccountAliappUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountAliapp]: def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountAliapp]:
return db.query(self.model).filter(self.model.uniacid == uniacid).first() return self.get_by_field(db, "uniacid", uniacid)
class CRUDAccountBaiduapp(CRUDBase[AccountBaiduapp, AccountBaiduappCreate, AccountBaiduappUpdate]): class CRUDAccountBaiduapp(CRUDBase[AccountBaiduapp, AccountBaiduappCreate, AccountBaiduappUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountBaiduapp]: def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountBaiduapp]:
return db.query(self.model).filter(self.model.uniacid == uniacid).first() return self.get_by_field(db, "uniacid", uniacid)
class CRUDAccountPhoneapp(CRUDBase[AccountPhoneapp, AccountPhoneappCreate, AccountPhoneappUpdate]): class CRUDAccountPhoneapp(CRUDBase[AccountPhoneapp, AccountPhoneappCreate, AccountPhoneappUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountPhoneapp]: def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountPhoneapp]:
return db.query(self.model).filter(self.model.uniacid == uniacid).first() return self.get_by_field(db, "uniacid", uniacid)
class CRUDAccountToutiaoapp(CRUDBase[AccountToutiaoapp, AccountToutiaoappCreate, AccountToutiaoappUpdate]): class CRUDAccountToutiaoapp(CRUDBase[AccountToutiaoapp, AccountToutiaoappCreate, AccountToutiaoappUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountToutiaoapp]: def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountToutiaoapp]:
return db.query(self.model).filter(self.model.uniacid == uniacid).first() return self.get_by_field(db, "uniacid", uniacid)
class CRUDAccountWebapp(CRUDBase[AccountWebapp, AccountWebappCreate, AccountWebappUpdate]): class CRUDAccountWebapp(CRUDBase[AccountWebapp, AccountWebappCreate, AccountWebappUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountWebapp]: def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountWebapp]:
return db.query(self.model).filter(self.model.uniacid == uniacid).first() return self.get_by_field(db, "uniacid", uniacid)
class CRUDAccountWxapp(CRUDBase[AccountWxapp, AccountWxappCreate, AccountWxappUpdate]): class CRUDAccountWxapp(CRUDBase[AccountWxapp, AccountWxappCreate, AccountWxappUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountWxapp]: def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountWxapp]:
return db.query(self.model).filter(self.model.uniacid == uniacid).first() return self.get_by_field(db, "uniacid", uniacid)
class CRUDAccountXzapp(CRUDBase[AccountXzapp, AccountXzappCreate, AccountXzappUpdate]): class CRUDAccountXzapp(CRUDBase[AccountXzapp, AccountXzappCreate, AccountXzappUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountXzapp]: def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[AccountXzapp]:
return db.query(self.model).filter(self.model.uniacid == uniacid).first() return self.get_by_field(db, "uniacid", uniacid)
class CRUDAccount(CRUDBase[Account, None, None]): # 创建实例
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[Account]:
return db.query(self.model).filter(self.model.uniacid == uniacid).first()
# 实例化所有CRUD对象
account = CRUDAccount(Account)
account_wechats = CRUDAccountWechats(AccountWechats) account_wechats = CRUDAccountWechats(AccountWechats)
account_aliapp = CRUDAccountAliapp(AccountAliapp) account_aliapp = CRUDAccountAliapp(AccountAliapp)
account_baiduapp = CRUDAccountBaiduapp(AccountBaiduapp) account_baiduapp = CRUDAccountBaiduapp(AccountBaiduapp)

View File

@ -1,54 +1,22 @@
from typing import List, Optional from typing import Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from mooc.crud.crud_base import CRUDBase
from mooc.models.admin import Admin from mooc.models.admin import Admin
from mooc.schemas.admin import AdminCreate, AdminUpdate from mooc.schemas.admin import AdminCreate, AdminUpdate
class CRUDAdmin(CRUDBase[Admin, AdminCreate, AdminUpdate]):
class CRUDAdmin: def get_by_username(self, db: Session, *, username: str) -> Optional[Admin]:
def get(self, db: Session, id: int) -> Optional[Admin]: return self.get_by_field(db, "username", username)
return db.query(Admin).filter(Admin.id == id).first()
def get_by_username(self, db: Session, username: str) -> Optional[Admin]:
return db.query(Admin).filter(Admin.username == username).first()
def get_multi(
self, db: Session, *, skip: int = 0, limit: int = 100
) -> List[Admin]:
return db.query(Admin).offset(skip).limit(limit).all()
def create(self, db: Session, *, obj_in: AdminCreate) -> Admin:
db_obj = Admin(
weid=obj_in.weid,
username=obj_in.username,
password=obj_in.password,
pcate_id=obj_in.pcate_id,
cate_id=obj_in.cate_id,
relation_id=obj_in.relation_id,
is_delete=obj_in.is_delete
)
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
def update(
self, db: Session, *, db_obj: Admin, obj_in: AdminUpdate
) -> Admin:
update_data = obj_in.dict(exclude_unset=True)
for field, value in update_data.items():
setattr(db_obj, field, value)
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
def delete(self, db: Session, *, id: int) -> Admin: def delete(self, db: Session, *, id: int) -> Admin:
obj = db.query(Admin).get(id) """重写删除方法,实现软删除"""
obj = self.get(db, id=id)
if obj: if obj:
obj.is_delete = 1 obj.is_delete = 1
db.add(obj) db.add(obj)
db.commit() db.commit()
db.refresh(obj)
return obj return obj
admin = CRUDAdmin() admin = CRUDAdmin(Admin)

View File

@ -2,9 +2,10 @@ from typing import Any, Dict, Generic, List, Optional, Type, TypeVar, Union
from fastapi.encoders import jsonable_encoder from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel from pydantic import BaseModel
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from sqlalchemy import Column
from mooc.db.database import Base from mooc.db.database import Base
ModelType = TypeVar("ModelType", bound=Base) ModelType = TypeVar("ModelType", bound="Base")
CreateSchemaType = TypeVar("CreateSchemaType", bound=BaseModel) CreateSchemaType = TypeVar("CreateSchemaType", bound=BaseModel)
UpdateSchemaType = TypeVar("UpdateSchemaType", bound=BaseModel) UpdateSchemaType = TypeVar("UpdateSchemaType", bound=BaseModel)
@ -18,8 +19,46 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
self.model = model self.model = model
def get(self, db: Session, id: Any) -> Optional[ModelType]: def get(self, db: Session, id: Any) -> Optional[ModelType]:
"""通过主键获取记录"""
return db.query(self.model).filter(self.model.acid == id).first() return db.query(self.model).filter(self.model.acid == id).first()
def get_by_field(
self,
db: Session,
field: str,
value: Any
) -> Optional[ModelType]:
"""
通过任意字段获取单条记录
Args:
db: 数据库会话
field: 字段名
value: 字段值
"""
return db.query(self.model).filter(getattr(self.model, field) == value).first()
def get_multi_by_field(
self,
db: Session,
field: str,
value: Any,
*,
skip: int = 0,
limit: int = 100
) -> List[ModelType]:
"""
通过任意字段获取多条记录
Args:
db: 数据库会话
field: 字段名
value: 字段值
skip: 跳过记录数
limit: 返回记录数限制
"""
return db.query(self.model).filter(
getattr(self.model, field) == value
).offset(skip).limit(limit).all()
def get_multi( def get_multi(
self, db: Session, *, skip: int = 0, limit: int = 100 self, db: Session, *, skip: int = 0, limit: int = 100
) -> List[ModelType]: ) -> List[ModelType]:

View File

@ -0,0 +1,110 @@
from typing import Optional
from sqlalchemy.orm import Session
from mooc.crud.crud_base import CRUDBase
from mooc.models.uni_account import (
UniAccount, UniAccountExtraModules,
UniAccountGroup, UniAccountMenus,
UniAccountModules,
UniAccountModulesShortcut,
UniAccountUsers,
UniGroup,
UniLinkUniacid,
UniModules,
UniVerifycode,
UniSettings
)
from mooc.schemas.uni_account import (
UniAccountCreate, UniAccountUpdate,
UniAccountExtraModulesCreate, UniAccountExtraModulesUpdate,
UniAccountGroupCreate, UniAccountGroupUpdate,
UniAccountMenusCreate, UniAccountMenusUpdate,
UniAccountModulesCreate, UniAccountModulesUpdate,
UniAccountModulesShortcutCreate, UniAccountModulesShortcutUpdate,
UniAccountUsersCreate, UniAccountUsersUpdate,
UniGroupCreate, UniGroupUpdate,
UniLinkUniacidCreate, UniLinkUniacidUpdate,
UniModulesCreate, UniModulesUpdate,
UniVerifycodeCreate, UniVerifycodeUpdate,
UniSettingsCreate, UniSettingsUpdate
)
class CRUDUniAccount(CRUDBase[UniAccount, UniAccountCreate, UniAccountUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniAccount]:
return self.get_by_field(db, "uniacid", uniacid)
class CRUDUniAccountExtraModules(CRUDBase[UniAccountExtraModules, UniAccountExtraModulesCreate, UniAccountExtraModulesUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniAccountExtraModules]:
return self.get_by_field(db, "uniacid", uniacid)
class CRUDUniAccountGroup(CRUDBase[UniAccountGroup, UniAccountGroupCreate, UniAccountGroupUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniAccountGroup]:
return self.get_by_field(db, "uniacid", uniacid)
class CRUDUniAccountMenus(CRUDBase[UniAccountMenus, UniAccountMenusCreate, UniAccountMenusUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniAccountMenus]:
return self.get_by_field(db, "uniacid", uniacid)
class CRUDUniAccountModules(CRUDBase[UniAccountModules, UniAccountModulesCreate, UniAccountModulesUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniAccountModules]:
return self.get_by_field(db, "uniacid", uniacid)
class CRUDUniAccountModulesShortcut(CRUDBase[UniAccountModulesShortcut, UniAccountModulesShortcutCreate, UniAccountModulesShortcutUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniAccountModulesShortcut]:
return self.get_by_field(db, "uniacid", uniacid)
class CRUDUniAccountUsers(CRUDBase[UniAccountUsers, UniAccountUsersCreate, UniAccountUsersUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniAccountUsers]:
return self.get_by_field(db, "uniacid", uniacid)
def get_by_uid(self, db: Session, *, uid: int) -> Optional[UniAccountUsers]:
return self.get_by_field(db, "uid", uid)
class CRUDUniGroup(CRUDBase[UniGroup, UniGroupCreate, UniGroupUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniGroup]:
return self.get_by_field(db, "uniacid", uniacid)
def get_by_owner(self, db: Session, *, owner_uid: int) -> Optional[UniGroup]:
return self.get_by_field(db, "owner_uid", owner_uid)
class CRUDUniLinkUniacid(CRUDBase[UniLinkUniacid, UniLinkUniacidCreate, UniLinkUniacidUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniLinkUniacid]:
return self.get_by_field(db, "uniacid", uniacid)
class CRUDUniModules(CRUDBase[UniModules, UniModulesCreate, UniModulesUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniModules]:
return self.get_by_field(db, "uniacid", uniacid)
class CRUDUniVerifycode(CRUDBase[UniVerifycode, UniVerifycodeCreate, UniVerifycodeUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniVerifycode]:
return self.get_by_field(db, "uniacid", uniacid)
def get_by_receiver(self, db: Session, *, receiver: str) -> Optional[UniVerifycode]:
return self.get_by_field(db, "receiver", receiver)
class CRUDUniSettings(CRUDBase[UniSettings, UniSettingsCreate, UniSettingsUpdate]):
def get_by_uniacid(self, db: Session, *, uniacid: int) -> Optional[UniSettings]:
return db.query(self.model).filter(self.model.uniacid == uniacid).first()
def create_with_uniacid(
self, db: Session, *, obj_in: UniSettingsCreate
) -> UniSettings:
"""创建设置时使用uniacid作为主键"""
db_obj = UniSettings(**obj_in.dict())
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
# 创建实例
uni_account = CRUDUniAccount(UniAccount)
uni_account_extra_modules = CRUDUniAccountExtraModules(UniAccountExtraModules)
uni_account_group = CRUDUniAccountGroup(UniAccountGroup)
uni_account_menus = CRUDUniAccountMenus(UniAccountMenus)
uni_account_modules = CRUDUniAccountModules(UniAccountModules)
uni_account_modules_shortcut = CRUDUniAccountModulesShortcut(UniAccountModulesShortcut)
uni_account_users = CRUDUniAccountUsers(UniAccountUsers)
uni_group = CRUDUniGroup(UniGroup)
uni_link_uniacid = CRUDUniLinkUniacid(UniLinkUniacid)
uni_modules = CRUDUniModules(UniModules)
uni_verifycode = CRUDUniVerifycode(UniVerifycode)
uni_settings = CRUDUniSettings(UniSettings)

View File

@ -9,5 +9,6 @@ from mooc.models.account import (
AccountWebapp, AccountWebapp,
AccountWxapp, AccountWxapp,
AccountXzapp, AccountXzapp,
Account, Account
) )
from mooc.models.uni_account import UniAccount, UniAccountExtraModules, UniAccountGroup, UniAccountMenus, UniAccountModules

View File

@ -1,8 +1,16 @@
from sqlalchemy import create_engine from sqlalchemy import create_engine, inspect
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
from mooc.core.config import settings from mooc.core.config import settings
from typing import Generator from typing import Generator, Set
import importlib
import pkgutil
from pathlib import Path
import logging
# 配置日志
logger = logging.getLogger(__name__)
# 创建数据库引擎 # 创建数据库引擎
engine = create_engine( engine = create_engine(
settings.SQLALCHEMY_DATABASE_URI, settings.SQLALCHEMY_DATABASE_URI,
@ -16,9 +24,61 @@ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# 创建基类 # 创建基类
Base = declarative_base() Base = declarative_base()
def init_db(): def get_existing_tables() -> Set[str]:
"""初始化数据库""" """获取数据库中已存在的表"""
Base.metadata.create_all(bind=engine) inspector = inspect(engine)
return set(inspector.get_table_names())
def import_models() -> None:
"""
自动导入所有模型
这确保所有模型类都被正确地注册到Base.metadata
"""
models_path = Path(__file__).parent.parent / "models"
for module_info in pkgutil.iter_modules([str(models_path)]):
importlib.import_module(f"mooc.models.{module_info.name}")
# 导入后立即验证
from mooc.models import verify_all_models
verify_all_models()
def create_missing_tables() -> None:
"""创建缺失的表"""
existing_tables = get_existing_tables()
metadata_tables = set(Base.metadata.tables.keys())
missing_tables = metadata_tables - existing_tables
if missing_tables:
logger.info(f"Creating missing tables: {missing_tables}")
# 只创建缺失的表
for table_name in missing_tables:
if table_name in Base.metadata.tables:
Base.metadata.tables[table_name].create(engine)
else:
logger.info("All tables already exist")
def init_db() -> None:
"""
初始化数据库
1. 导入所有模型并验证
2. 检查并创建缺失的表
"""
try:
# 确保所有模型都被导入并验证
import_models()
logger.info("All models imported successfully")
# 创建缺失的表
create_missing_tables()
logger.info("Database initialization completed successfully")
# 打印所有已注册的表名(用于调试)
from mooc.models import get_all_table_names
logger.debug(f"Registered tables: {get_all_table_names()}")
except Exception as e:
logger.error(f"Database initialization failed: {str(e)}")
raise
def get_db() -> Generator: def get_db() -> Generator:
""" """

View File

@ -0,0 +1,82 @@
# 显式导入所有模型模块
from mooc.models.admin import * # noqa
from mooc.models.account import * # noqa
from mooc.models.uni_account import * # noqa
# 导出常用的模型类
from mooc.models.account import (
Account,
AccountWechats,
AccountAliapp,
AccountBaiduapp,
AccountPhoneapp,
AccountToutiaoapp,
AccountWebapp,
AccountWxapp,
AccountXzapp
)
from mooc.models.uni_account import (
UniAccount,
UniAccountExtraModules,
UniAccountGroup,
UniAccountMenus,
UniAccountModules,
UniAccountModulesShortcut,
UniAccountUsers,
UniGroup,
UniLinkUniacid,
UniModules,
UniSettings,
UniVerifycode
)
def verify_all_models():
"""验证所有模型是否已正确注册到Base.metadata"""
from mooc.db.database import Base
# 所有预期的表名
expected_tables = {
'ims_goouc_fullexam_admin',
# Account 相关表
'ims_account',
'ims_account_aliapp',
'ims_account_baiduapp',
'ims_account_phoneapp',
'ims_account_toutiaoapp',
'ims_account_webapp',
'ims_account_wechats',
'ims_account_wxapp',
'ims_account_xzapp',
# UniAccount 相关表
'ims_uni_account',
'ims_uni_account_extra_modules',
'ims_uni_account_group',
'ims_uni_account_menus',
'ims_uni_account_modules',
'ims_uni_account_modules_shortcut',
'ims_uni_account_users',
'ims_uni_group',
'ims_uni_link_uniacid',
'ims_uni_modules',
'ims_uni_settings',
'ims_uni_verifycode'
}
actual_tables = set(Base.metadata.tables.keys())
missing_tables = expected_tables - actual_tables
extra_tables = actual_tables - expected_tables
if missing_tables:
raise RuntimeError(f"Missing tables in metadata: {missing_tables}")
if extra_tables:
print(f"Warning: Found unexpected tables: {extra_tables}")
return True
def get_all_table_names():
"""获取所有已注册的表名"""
from mooc.db.database import Base
return sorted(Base.metadata.tables.keys())

187
mooc/models/uni_account.py Normal file
View File

@ -0,0 +1,187 @@
from sqlalchemy import Column, Integer, String, Text, SmallInteger
from mooc.db.database import Base
class UniAccount(Base):
__tablename__ = "ims_uni_account"
uniacid = Column(Integer, primary_key=True, autoincrement=True)
groupid = Column(Integer, nullable=False)
name = Column(String(100), nullable=False)
description = Column(String(255), nullable=False)
default_acid = Column(Integer, nullable=False)
rank = Column(Integer)
title_initial = Column(String(1), nullable=False)
createtime = Column(Integer, nullable=False)
logo = Column(String(255), nullable=False)
qrcode = Column(String(255), nullable=False)
create_uid = Column(Integer, nullable=False)
class Config:
from_attributes = True
class UniAccountExtraModules(Base):
__tablename__ = "ims_uni_account_extra_modules"
id = Column(Integer, primary_key=True, autoincrement=True)
uniacid = Column(Integer, index=True, nullable=False)
modules = Column(Text, nullable=False)
class Config:
from_attributes = True
class UniAccountGroup(Base):
__tablename__ = "ims_uni_account_group"
id = Column(Integer, primary_key=True, autoincrement=True)
uniacid = Column(Integer, nullable=False)
groupid = Column(Integer, nullable=False)
class Config:
from_attributes = True
class UniAccountMenus(Base):
__tablename__ = "ims_uni_account_menus"
id = Column(Integer, primary_key=True, autoincrement=True)
uniacid = Column(Integer, index=True, nullable=False)
menuid = Column(Integer, index=True, nullable=False)
type = Column(SmallInteger, nullable=False)
title = Column(String(30), nullable=False)
sex = Column(SmallInteger, nullable=False)
group_id = Column(Integer, nullable=False)
client_platform_type = Column(SmallInteger, nullable=False)
area = Column(String(50), nullable=False)
data = Column(Text, nullable=False)
status = Column(SmallInteger, nullable=False)
createtime = Column(Integer, nullable=False)
isdeleted = Column(SmallInteger, nullable=False)
class Config:
from_attributes = True
class UniAccountModules(Base):
__tablename__ = "ims_uni_account_modules"
id = Column(Integer, primary_key=True, autoincrement=True)
uniacid = Column(Integer, index=True, nullable=False)
module = Column(String(50), index=True, nullable=False)
enabled = Column(SmallInteger, nullable=False)
settings = Column(Text, nullable=False)
shortcut = Column(SmallInteger, nullable=False)
displayorder = Column(Integer, nullable=False)
class Config:
from_attributes = True
class UniAccountModulesShortcut(Base):
__tablename__ = "ims_uni_account_modules_shortcut"
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(200), nullable=False)
url = Column(String(250), nullable=False)
icon = Column(String(200), nullable=False)
uniacid = Column(Integer, nullable=False)
version_id = Column(Integer, nullable=False)
module_name = Column(String(200), nullable=False)
class Config:
from_attributes = True
class UniAccountUsers(Base):
__tablename__ = "ims_uni_account_users"
id = Column(Integer, primary_key=True, autoincrement=True)
uniacid = Column(Integer, index=True, nullable=False)
uid = Column(Integer, index=True, nullable=False)
role = Column(String(255), nullable=False)
rank = Column(SmallInteger, nullable=False)
class Config:
from_attributes = True
class UniGroup(Base):
__tablename__ = "ims_uni_group"
id = Column(Integer, primary_key=True, autoincrement=True)
owner_uid = Column(Integer, nullable=False)
name = Column(String(50), nullable=False)
modules = Column(Text, nullable=False)
templates = Column(String(5000), nullable=False)
uniacid = Column(Integer, index=True, nullable=False)
uid = Column(Integer, nullable=False)
class Config:
from_attributes = True
class UniLinkUniacid(Base):
__tablename__ = "ims_uni_link_uniacid"
id = Column(Integer, primary_key=True, autoincrement=True)
uniacid = Column(Integer, nullable=False)
link_uniacid = Column(Integer, nullable=False)
version_id = Column(Integer, nullable=False)
module_name = Column(String(255), nullable=False)
class Config:
from_attributes = True
class UniModules(Base):
__tablename__ = "ims_uni_modules"
id = Column(Integer, primary_key=True, autoincrement=True)
uniacid = Column(Integer, index=True, nullable=False)
module_name = Column(String(50), nullable=False)
class Config:
from_attributes = True
class UniVerifycode(Base):
__tablename__ = "ims_uni_verifycode"
id = Column(Integer, primary_key=True, autoincrement=True)
uniacid = Column(Integer, nullable=False)
receiver = Column(String(50), nullable=False)
verifycode = Column(String(6), nullable=False)
total = Column(SmallInteger, nullable=False)
createtime = Column(Integer, nullable=False)
failed_count = Column(Integer)
class Config:
from_attributes = True
class UniSettings(Base):
__tablename__ = "ims_uni_settings"
uniacid = Column(Integer, primary_key=True)
passport = Column(String(200), nullable=False)
oauth = Column(String(100), nullable=False)
jsauth_acid = Column(Integer, nullable=False)
notify = Column(String(2000), nullable=False)
creditnames = Column(String(500), nullable=False)
creditbehaviors = Column(String(500), nullable=False)
welcome = Column(String(60), nullable=False)
default = Column(String(60), nullable=False)
default_message = Column(String(2000), nullable=False)
payment = Column(Text, nullable=False)
stat = Column(String(300), nullable=False)
default_site = Column(Integer)
sync = Column(SmallInteger, nullable=False)
recharge = Column(String(500), nullable=False)
tplnotice = Column(String(2000), nullable=False)
grouplevel = Column(SmallInteger, nullable=False)
mcplugin = Column(String(500), nullable=False)
exchange_enable = Column(SmallInteger, nullable=False)
coupon_type = Column(SmallInteger, nullable=False)
menuset = Column(Text, nullable=False)
statistics = Column(String(100), nullable=False)
bind_domain = Column(String(200), nullable=False)
comment_status = Column(SmallInteger, nullable=False)
reply_setting = Column(SmallInteger, nullable=False)
default_module = Column(String(100), nullable=False)
attachment_limit = Column(Integer, nullable=False)
attachment_size = Column(String(20), nullable=False)
sync_member = Column(SmallInteger, nullable=False)
remote = Column(String(2000), nullable=False)
class Config:
from_attributes = True

319
mooc/schemas/uni_account.py Normal file
View File

@ -0,0 +1,319 @@
from pydantic import BaseModel
from typing import Optional
class UniAccountBase(BaseModel):
groupid: int
name: str
description: str
default_acid: int
rank: Optional[int]
title_initial: str
createtime: int
logo: str
qrcode: str
create_uid: int
class UniAccountCreate(UniAccountBase):
pass
class UniAccountUpdate(BaseModel):
groupid: Optional[int]
name: Optional[str]
description: Optional[str]
default_acid: Optional[int]
rank: Optional[int]
title_initial: Optional[str]
logo: Optional[str]
qrcode: Optional[str]
create_uid: Optional[int]
class UniAccountRead(UniAccountBase):
uniacid: int
class Config:
from_attributes = True
class UniAccountExtraModulesBase(BaseModel):
uniacid: int
modules: str
class UniAccountExtraModulesCreate(UniAccountExtraModulesBase):
pass
class UniAccountExtraModulesUpdate(BaseModel):
modules: Optional[str]
class UniAccountExtraModulesRead(UniAccountExtraModulesBase):
id: int
class Config:
from_attributes = True
class UniAccountGroupBase(BaseModel):
uniacid: int
groupid: int
class UniAccountGroupCreate(UniAccountGroupBase):
pass
class UniAccountGroupUpdate(BaseModel):
groupid: Optional[int]
class UniAccountGroupRead(UniAccountGroupBase):
id: int
class Config:
from_attributes = True
class UniAccountMenusBase(BaseModel):
uniacid: int
menuid: int
type: int
title: str
sex: int
group_id: int
client_platform_type: int
area: str
data: str
status: int
createtime: int
isdeleted: int
class UniAccountMenusCreate(UniAccountMenusBase):
pass
class UniAccountMenusUpdate(BaseModel):
type: Optional[int]
title: Optional[str]
sex: Optional[int]
group_id: Optional[int]
client_platform_type: Optional[int]
area: Optional[str]
data: Optional[str]
status: Optional[int]
isdeleted: Optional[int]
class UniAccountMenusRead(UniAccountMenusBase):
id: int
class Config:
from_attributes = True
class UniAccountModulesBase(BaseModel):
uniacid: int
module: str
enabled: int
settings: str
shortcut: int
displayorder: int
class UniAccountModulesCreate(UniAccountModulesBase):
pass
class UniAccountModulesUpdate(BaseModel):
module: Optional[str]
enabled: Optional[int]
settings: Optional[str]
shortcut: Optional[int]
displayorder: Optional[int]
class UniAccountModulesRead(UniAccountModulesBase):
id: int
class Config:
from_attributes = True
class UniAccountModulesShortcutBase(BaseModel):
title: str
url: str
icon: str
uniacid: int
version_id: int
module_name: str
class UniAccountModulesShortcutCreate(UniAccountModulesShortcutBase):
pass
class UniAccountModulesShortcutUpdate(BaseModel):
title: Optional[str]
url: Optional[str]
icon: Optional[str]
version_id: Optional[int]
module_name: Optional[str]
class UniAccountModulesShortcutRead(UniAccountModulesShortcutBase):
id: int
class Config:
from_attributes = True
class UniAccountUsersBase(BaseModel):
uniacid: int
uid: int
role: str
rank: int
class UniAccountUsersCreate(UniAccountUsersBase):
pass
class UniAccountUsersUpdate(BaseModel):
role: Optional[str]
rank: Optional[int]
class UniAccountUsersRead(UniAccountUsersBase):
id: int
class Config:
from_attributes = True
class UniGroupBase(BaseModel):
owner_uid: int
name: str
modules: str
templates: str
uniacid: int
uid: int
class UniGroupCreate(UniGroupBase):
pass
class UniGroupUpdate(BaseModel):
name: Optional[str]
modules: Optional[str]
templates: Optional[str]
owner_uid: Optional[int]
uid: Optional[int]
class UniGroupRead(UniGroupBase):
id: int
class Config:
from_attributes = True
class UniLinkUniacidBase(BaseModel):
uniacid: int
link_uniacid: int
version_id: int
module_name: str
class UniLinkUniacidCreate(UniLinkUniacidBase):
pass
class UniLinkUniacidUpdate(BaseModel):
link_uniacid: Optional[int]
version_id: Optional[int]
module_name: Optional[str]
class UniLinkUniacidRead(UniLinkUniacidBase):
id: int
class Config:
from_attributes = True
class UniModulesBase(BaseModel):
uniacid: int
module_name: str
class UniModulesCreate(UniModulesBase):
pass
class UniModulesUpdate(BaseModel):
module_name: Optional[str]
class UniModulesRead(UniModulesBase):
id: int
class Config:
from_attributes = True
class UniVerifycodeBase(BaseModel):
uniacid: int
receiver: str
verifycode: str
total: int
createtime: int
failed_count: Optional[int]
class UniVerifycodeCreate(UniVerifycodeBase):
pass
class UniVerifycodeUpdate(BaseModel):
verifycode: Optional[str]
total: Optional[int]
failed_count: Optional[int]
class UniVerifycodeRead(UniVerifycodeBase):
id: int
class Config:
from_attributes = True
class UniSettingsBase(BaseModel):
uniacid: int
passport: str
oauth: str
jsauth_acid: int
notify: str
creditnames: str
creditbehaviors: str
welcome: str
default: str
default_message: str
payment: str
stat: str
default_site: Optional[int]
sync: int
recharge: str
tplnotice: str
grouplevel: int
mcplugin: str
exchange_enable: int
coupon_type: int
menuset: str
statistics: str
bind_domain: str
comment_status: int
reply_setting: int
default_module: str
attachment_limit: int
attachment_size: str
sync_member: int
remote: str
class UniSettingsCreate(UniSettingsBase):
pass
class UniSettingsUpdate(BaseModel):
passport: Optional[str]
oauth: Optional[str]
jsauth_acid: Optional[int]
notify: Optional[str]
creditnames: Optional[str]
creditbehaviors: Optional[str]
welcome: Optional[str]
default: Optional[str]
default_message: Optional[str]
payment: Optional[str]
stat: Optional[str]
default_site: Optional[int]
sync: Optional[int]
recharge: Optional[str]
tplnotice: Optional[str]
grouplevel: Optional[int]
mcplugin: Optional[str]
exchange_enable: Optional[int]
coupon_type: Optional[int]
menuset: Optional[str]
statistics: Optional[str]
bind_domain: Optional[str]
comment_status: Optional[int]
reply_setting: Optional[int]
default_module: Optional[str]
attachment_limit: Optional[int]
attachment_size: Optional[str]
sync_member: Optional[int]
remote: Optional[str]
class UniSettingsRead(UniSettingsBase):
class Config:
from_attributes = True