faster-app 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- faster_app/__init__.py +58 -0
- faster_app/base.py +129 -0
- faster_app/commands/__init__.py +14 -0
- faster_app/commands/base.py +85 -0
- faster_app/commands/builtins/__init__.py +3 -0
- faster_app/commands/builtins/db.py +137 -0
- faster_app/commands/builtins/fastapi.py +87 -0
- faster_app/commands/discover.py +24 -0
- faster_app/db.py +32 -0
- faster_app/models/__init__.py +21 -0
- faster_app/models/base.py +106 -0
- faster_app/models/discover.py +53 -0
- faster_app/routes/__init__.py +13 -0
- faster_app/routes/base.py +12 -0
- faster_app/routes/builtins/__init__.py +3 -0
- faster_app/routes/builtins/defaults.py +12 -0
- faster_app/routes/builtins/swagger.py +15 -0
- faster_app/routes/discover.py +52 -0
- faster_app/settings/__init__.py +10 -0
- faster_app/settings/builtins/settings.py +64 -0
- faster_app/settings/discover.py +79 -0
- faster_app/statics/swagger-ui-bundle.min.js +11 -0
- faster_app/statics/swagger-ui.min.css +1 -0
- faster_app-0.0.1.dist-info/METADATA +285 -0
- faster_app-0.0.1.dist-info/RECORD +28 -0
- faster_app-0.0.1.dist-info/WHEEL +5 -0
- faster_app-0.0.1.dist-info/licenses/LICENSE +21 -0
- faster_app-0.0.1.dist-info/top_level.txt +1 -0
faster_app/__init__.py
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
"""
|
2
|
+
Faster API - 一个轻量级的 Python Web 框架
|
3
|
+
|
4
|
+
提供了以下核心功能:
|
5
|
+
- 自动发现和加载模块 (DiscoverBase)
|
6
|
+
- 数据库模型基类 (UUIDModel, DateTimeModel, StatusModel, ScopeModel)
|
7
|
+
- 命令行工具基类 (CommandBase)
|
8
|
+
- 路由管理 (ApiResponse)
|
9
|
+
- 数据库连接管理 (tortoise_init)
|
10
|
+
"""
|
11
|
+
|
12
|
+
__version__ = "0.0.1"
|
13
|
+
__author__ = "peizhenfei"
|
14
|
+
__email__ = "peizhenfei@hotmail.com"
|
15
|
+
|
16
|
+
# 导出主要的类和函数
|
17
|
+
from faster_app.base import DiscoverBase
|
18
|
+
from faster_app.models.base import (
|
19
|
+
UUIDModel,
|
20
|
+
DateTimeModel,
|
21
|
+
StatusModel,
|
22
|
+
ScopeModel,
|
23
|
+
SyncTimeModel,
|
24
|
+
SyncCrontabModel,
|
25
|
+
)
|
26
|
+
from faster_app.commands.base import CommandBase, with_db_init
|
27
|
+
from faster_app.routes.base import ApiResponse
|
28
|
+
from faster_app.db import tortoise_init
|
29
|
+
|
30
|
+
# 导出发现器
|
31
|
+
from faster_app.models.discover import ModelDiscover
|
32
|
+
from faster_app.commands.discover import CommandDiscover
|
33
|
+
from faster_app.routes.discover import RoutesDiscover
|
34
|
+
|
35
|
+
# 导出配置
|
36
|
+
from faster_app.settings.builtins.settings import DefaultSettings
|
37
|
+
|
38
|
+
__all__ = [
|
39
|
+
# 基础类
|
40
|
+
"DiscoverBase",
|
41
|
+
"CommandBase",
|
42
|
+
"with_db_init",
|
43
|
+
"ApiResponse",
|
44
|
+
"tortoise_init",
|
45
|
+
# 模型基类
|
46
|
+
"UUIDModel",
|
47
|
+
"DateTimeModel",
|
48
|
+
"StatusModel",
|
49
|
+
"ScopeModel",
|
50
|
+
"SyncTimeModel",
|
51
|
+
"SyncCrontabModel",
|
52
|
+
# 发现器
|
53
|
+
"ModelDiscover",
|
54
|
+
"CommandDiscover",
|
55
|
+
"RoutesDiscover",
|
56
|
+
# 配置
|
57
|
+
"DefaultSettings",
|
58
|
+
]
|
faster_app/base.py
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
import os
|
2
|
+
import importlib.util
|
3
|
+
import inspect
|
4
|
+
from typing import Dict, List
|
5
|
+
|
6
|
+
|
7
|
+
class DiscoverBase(object):
|
8
|
+
INSTANCE_TYPE = None
|
9
|
+
TARGETS: List[Dict[str, str]] = []
|
10
|
+
|
11
|
+
def discover(self) -> List[type]:
|
12
|
+
"""
|
13
|
+
自动扫描 TARGETS 中的目录和文件,
|
14
|
+
导出所有的实例
|
15
|
+
"""
|
16
|
+
instances = []
|
17
|
+
|
18
|
+
# 扫描 TARGETS 中的目录和文件
|
19
|
+
for target in self.TARGETS:
|
20
|
+
instances.extend(
|
21
|
+
self.scan(
|
22
|
+
directory=target.get("directory"),
|
23
|
+
filename=target.get("filename"),
|
24
|
+
skip_files=target.get("skip_files"),
|
25
|
+
skip_dirs=target.get("skip_dirs"),
|
26
|
+
)
|
27
|
+
)
|
28
|
+
# print(instances)
|
29
|
+
return instances
|
30
|
+
|
31
|
+
def walk(
|
32
|
+
self,
|
33
|
+
directory: str,
|
34
|
+
filename: str = None,
|
35
|
+
skip_files: List[str] = [],
|
36
|
+
skip_dirs: List[str] = [],
|
37
|
+
) -> List[str]:
|
38
|
+
"""
|
39
|
+
遍历目录下的所有文件
|
40
|
+
"""
|
41
|
+
results = []
|
42
|
+
if not os.path.exists(directory) or not os.path.isdir(directory):
|
43
|
+
return results
|
44
|
+
|
45
|
+
for root, dirs, files in os.walk(directory):
|
46
|
+
# 过滤掉需要跳过的目录,直接修改 dirs 列表来影响 os.walk 的遍历
|
47
|
+
dirs[:] = [d for d in dirs if d not in skip_dirs]
|
48
|
+
|
49
|
+
for file in files:
|
50
|
+
if filename is None or file == filename:
|
51
|
+
if file in skip_files:
|
52
|
+
continue
|
53
|
+
# 只处理 .py 文件
|
54
|
+
if file.endswith(".py"):
|
55
|
+
results.append(os.path.join(root, file))
|
56
|
+
return results
|
57
|
+
|
58
|
+
def scan(
|
59
|
+
self,
|
60
|
+
directory: str,
|
61
|
+
filename: str = None,
|
62
|
+
skip_files: List[str] = [],
|
63
|
+
skip_dirs: List[str] = [],
|
64
|
+
) -> List[type]:
|
65
|
+
"""
|
66
|
+
通用扫描方法
|
67
|
+
|
68
|
+
Args:
|
69
|
+
directory: 要扫描的目录路径
|
70
|
+
filename: 要扫描的具体文件名,如果为 None 则扫描目录下所有 .py 文件
|
71
|
+
skip_files: 要跳过的文件列表
|
72
|
+
skip_dirs: 要跳过的目录列表
|
73
|
+
Returns:
|
74
|
+
扫描到的所有实例列表
|
75
|
+
"""
|
76
|
+
instances = []
|
77
|
+
|
78
|
+
files = self.walk(directory, filename, skip_files, skip_dirs)
|
79
|
+
|
80
|
+
for file in files:
|
81
|
+
instances.extend(
|
82
|
+
self.import_and_extract_instances(file, file.split("/")[-1][:-3])
|
83
|
+
)
|
84
|
+
|
85
|
+
return instances
|
86
|
+
|
87
|
+
def import_and_extract_instances(
|
88
|
+
self, file_path: str, module_name: str
|
89
|
+
) -> List[type]:
|
90
|
+
"""
|
91
|
+
导入模块并提取实例
|
92
|
+
|
93
|
+
Args:
|
94
|
+
file_path: 文件路径
|
95
|
+
module_name: 模块名称
|
96
|
+
|
97
|
+
Returns:
|
98
|
+
提取到的实例列表
|
99
|
+
"""
|
100
|
+
instances = []
|
101
|
+
|
102
|
+
try:
|
103
|
+
# 动态导入模块
|
104
|
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
105
|
+
if spec is None or spec.loader is None:
|
106
|
+
return instances
|
107
|
+
|
108
|
+
module = importlib.util.module_from_spec(spec)
|
109
|
+
spec.loader.exec_module(module)
|
110
|
+
|
111
|
+
# 查找模块中所有的类并实例化
|
112
|
+
for _, obj in inspect.getmembers(module):
|
113
|
+
if (
|
114
|
+
inspect.isclass(obj)
|
115
|
+
and issubclass(obj, self.INSTANCE_TYPE)
|
116
|
+
and obj != self.INSTANCE_TYPE
|
117
|
+
):
|
118
|
+
try:
|
119
|
+
# 实例化命令类
|
120
|
+
instance = obj()
|
121
|
+
instances.append(instance)
|
122
|
+
except Exception as e:
|
123
|
+
print(f"Warning: Failed to instantiate {obj.__name__}: {e}")
|
124
|
+
|
125
|
+
except Exception as e:
|
126
|
+
# 静默跳过导入失败的模块,避免阻断整个发现过程
|
127
|
+
print(f"Warning: Failed to import instances from {module_name}: {e}")
|
128
|
+
|
129
|
+
return instances
|
@@ -0,0 +1,85 @@
|
|
1
|
+
"""
|
2
|
+
命令基类, 使用 fire 库管理子命令
|
3
|
+
"""
|
4
|
+
|
5
|
+
import inspect
|
6
|
+
from functools import wraps
|
7
|
+
from tortoise import Tortoise
|
8
|
+
from faster_app.db import tortoise_init
|
9
|
+
|
10
|
+
|
11
|
+
def with_db_init(func):
|
12
|
+
"""装饰器:为异步方法自动初始化和关闭数据库连接"""
|
13
|
+
|
14
|
+
@wraps(func)
|
15
|
+
async def wrapper(*args, **kwargs):
|
16
|
+
# 初始化数据库连接
|
17
|
+
await tortoise_init()
|
18
|
+
try:
|
19
|
+
# 执行原方法
|
20
|
+
result = await func(*args, **kwargs)
|
21
|
+
return result
|
22
|
+
finally:
|
23
|
+
# 关闭数据库连接
|
24
|
+
if Tortoise._inited:
|
25
|
+
await Tortoise.close_connections()
|
26
|
+
|
27
|
+
return wrapper
|
28
|
+
|
29
|
+
|
30
|
+
class CommandBase(object):
|
31
|
+
"""命令基类"""
|
32
|
+
|
33
|
+
# 默认要去掉的后缀列表
|
34
|
+
DEFAULT_SUFFIXES = [
|
35
|
+
"Command",
|
36
|
+
"Commands",
|
37
|
+
"Handler",
|
38
|
+
"Handlers",
|
39
|
+
"Operations",
|
40
|
+
"Operation",
|
41
|
+
]
|
42
|
+
|
43
|
+
def __getattribute__(self, name):
|
44
|
+
"""自动为异步方法添加数据库初始化装饰器"""
|
45
|
+
attr = object.__getattribute__(self, name)
|
46
|
+
|
47
|
+
# 如果是方法且是异步的,自动添加数据库初始化装饰器
|
48
|
+
if (
|
49
|
+
inspect.iscoroutinefunction(attr)
|
50
|
+
and not name.startswith("_")
|
51
|
+
and not hasattr(attr, "_db_wrapped")
|
52
|
+
):
|
53
|
+
wrapped_attr = with_db_init(attr)
|
54
|
+
wrapped_attr._db_wrapped = True # 标记已包装,避免重复包装
|
55
|
+
return wrapped_attr
|
56
|
+
|
57
|
+
return attr
|
58
|
+
|
59
|
+
@classmethod
|
60
|
+
def get_command_name(cls, class_name: str = None, suffixes: list = None) -> str:
|
61
|
+
"""
|
62
|
+
自动去除类名中的常见后缀,生成简洁的命令名
|
63
|
+
|
64
|
+
Args:
|
65
|
+
class_name: 类名,如果不提供则使用当前类的名称
|
66
|
+
suffixes: 要去除的后缀列表,如果不提供则使用默认后缀
|
67
|
+
|
68
|
+
Returns:
|
69
|
+
去除后缀后的命令名(小写)
|
70
|
+
"""
|
71
|
+
if class_name is None:
|
72
|
+
class_name = cls.__name__
|
73
|
+
|
74
|
+
if suffixes is None:
|
75
|
+
suffixes = cls.DEFAULT_SUFFIXES
|
76
|
+
|
77
|
+
# 按照后缀长度从长到短排序,优先匹配较长的后缀
|
78
|
+
sorted_suffixes = sorted(suffixes, key=len, reverse=True)
|
79
|
+
|
80
|
+
for suffix in sorted_suffixes:
|
81
|
+
if class_name.endswith(suffix):
|
82
|
+
return class_name[: -len(suffix)].lower()
|
83
|
+
|
84
|
+
# 如果没有匹配的后缀,直接返回小写的类名
|
85
|
+
return class_name.lower()
|
@@ -0,0 +1,137 @@
|
|
1
|
+
"""系统内置命令"""
|
2
|
+
|
3
|
+
import os
|
4
|
+
import shutil
|
5
|
+
from faster_app.commands.base import CommandBase
|
6
|
+
from rich.console import Console
|
7
|
+
from faster_app.settings.builtins.settings import DefaultSettings
|
8
|
+
from faster_app.models.discover import ModelDiscover
|
9
|
+
from aerich import Command
|
10
|
+
|
11
|
+
console = Console()
|
12
|
+
|
13
|
+
|
14
|
+
class DBOperations(CommandBase):
|
15
|
+
"""数据库操作命令 - 使用Aerich管理数据库迁移"""
|
16
|
+
|
17
|
+
def __init__(self, fake: bool = False):
|
18
|
+
self.fake = fake
|
19
|
+
self.command = Command(
|
20
|
+
tortoise_config=self._get_tortoise_config(), app="aerich"
|
21
|
+
)
|
22
|
+
|
23
|
+
def _get_tortoise_config(self):
|
24
|
+
"""获取Tortoise ORM配置"""
|
25
|
+
apps_models = ModelDiscover().discover()
|
26
|
+
# print("--->", apps_models) # 注释掉调试输出
|
27
|
+
configs = DefaultSettings()
|
28
|
+
tortoise_config = configs.TORTOISE_ORM.copy()
|
29
|
+
|
30
|
+
# 清空原有的apps配置
|
31
|
+
tortoise_config["apps"] = {}
|
32
|
+
|
33
|
+
# 为每个app创建配置
|
34
|
+
for app_name, models in apps_models.items():
|
35
|
+
tortoise_config["apps"][app_name] = {
|
36
|
+
"models": models,
|
37
|
+
"default_connection": "development" if configs.DEBUG else "production",
|
38
|
+
}
|
39
|
+
|
40
|
+
# 添加aerich模型到一个单独的app中
|
41
|
+
tortoise_config["apps"]["aerich"] = {
|
42
|
+
"models": ["aerich.models"],
|
43
|
+
"default_connection": "development" if configs.DEBUG else "production",
|
44
|
+
}
|
45
|
+
|
46
|
+
return tortoise_config
|
47
|
+
|
48
|
+
async def init_db(self):
|
49
|
+
"""初始化数据库(首次创建表)"""
|
50
|
+
try:
|
51
|
+
await self.command.init_db(safe=True)
|
52
|
+
console.print("✅ 数据库初始化成功")
|
53
|
+
except Exception as e:
|
54
|
+
console.print(f"❌ 数据库初始化失败: {e}")
|
55
|
+
finally:
|
56
|
+
await self.command.close()
|
57
|
+
|
58
|
+
async def migrate(self):
|
59
|
+
"""执行数据库迁移"""
|
60
|
+
try:
|
61
|
+
await self.command.init()
|
62
|
+
await self.command.migrate()
|
63
|
+
console.print("✅ 数据库迁移执行成功")
|
64
|
+
except Exception as e:
|
65
|
+
console.print(f"❌ 数据库迁移执行失败: {e}")
|
66
|
+
finally:
|
67
|
+
await self.command.close()
|
68
|
+
|
69
|
+
async def upgrade(self):
|
70
|
+
"""执行数据库迁移"""
|
71
|
+
try:
|
72
|
+
await self.command.init()
|
73
|
+
await self.command.upgrade(fake=self.fake)
|
74
|
+
console.print("✅ 数据库迁移执行成功")
|
75
|
+
except Exception as e:
|
76
|
+
console.print(f"❌ 数据库迁移执行失败: {e}")
|
77
|
+
finally:
|
78
|
+
await self.command.close()
|
79
|
+
|
80
|
+
async def downgrade(self, version: int = -1):
|
81
|
+
"""回滚数据库迁移"""
|
82
|
+
try:
|
83
|
+
await self.command.init()
|
84
|
+
await self.command.downgrade(version=version, delete=True, fake=self.fake)
|
85
|
+
console.print("✅ 数据库回滚成功")
|
86
|
+
except Exception as e:
|
87
|
+
console.print(f"❌ 数据库回滚失败: {e}")
|
88
|
+
finally:
|
89
|
+
await self.command.close()
|
90
|
+
|
91
|
+
async def history(self):
|
92
|
+
"""查看迁移历史"""
|
93
|
+
try:
|
94
|
+
await self.command.init()
|
95
|
+
history = await self.command.history()
|
96
|
+
console.print("✅ 迁移历史:")
|
97
|
+
for record in history:
|
98
|
+
console.print(f" - {record}")
|
99
|
+
|
100
|
+
except Exception as e:
|
101
|
+
console.print(f"❌ 查看迁移历史失败: {e}")
|
102
|
+
finally:
|
103
|
+
await self.command.close()
|
104
|
+
|
105
|
+
async def heads(self):
|
106
|
+
"""查看当前迁移头部"""
|
107
|
+
try:
|
108
|
+
await self.command.init()
|
109
|
+
heads = await self.command.heads()
|
110
|
+
console.print("✅ 当前迁移头部:")
|
111
|
+
for record in heads:
|
112
|
+
console.print(f" - {record}")
|
113
|
+
except Exception as e:
|
114
|
+
console.print(f"❌ 查看当前迁移头部失败: {e}")
|
115
|
+
finally:
|
116
|
+
await self.command.close()
|
117
|
+
|
118
|
+
async def dev_clean(self):
|
119
|
+
"""清理开发环境数据
|
120
|
+
1. 移除 sqlite 数据库文件
|
121
|
+
2. 移除 aerich 迁移记录
|
122
|
+
"""
|
123
|
+
try:
|
124
|
+
# 删除数据库文件
|
125
|
+
db_file = f"{configs.DB_DATABASE}.db"
|
126
|
+
if os.path.exists(db_file):
|
127
|
+
os.remove(db_file)
|
128
|
+
console.print(f"✅ 已删除数据库文件: {db_file}")
|
129
|
+
|
130
|
+
# 递归删除 migrations 目录
|
131
|
+
if os.path.exists("migrations"):
|
132
|
+
shutil.rmtree("migrations")
|
133
|
+
console.print("✅ 已删除迁移目录: migrations")
|
134
|
+
|
135
|
+
console.print("✅ 开发环境数据清理成功")
|
136
|
+
except Exception as e:
|
137
|
+
console.print(f"❌ 清理开发环境数据失败: {e}")
|
@@ -0,0 +1,87 @@
|
|
1
|
+
from contextlib import asynccontextmanager
|
2
|
+
from fastapi import FastAPI
|
3
|
+
from tortoise import Tortoise
|
4
|
+
from faster_app.settings.builtins.settings import DefaultSettings
|
5
|
+
from rich.console import Console
|
6
|
+
from starlette.staticfiles import StaticFiles
|
7
|
+
from faster_app.commands.base import CommandBase
|
8
|
+
from faster_app.db import tortoise_init
|
9
|
+
import uvicorn
|
10
|
+
import threading
|
11
|
+
|
12
|
+
from faster_app.routes.discover import RoutesDiscover
|
13
|
+
|
14
|
+
console = Console()
|
15
|
+
|
16
|
+
|
17
|
+
@asynccontextmanager
|
18
|
+
async def lifespan(app: FastAPI):
|
19
|
+
await tortoise_init()
|
20
|
+
yield
|
21
|
+
await Tortoise.close_connections()
|
22
|
+
|
23
|
+
|
24
|
+
class FastAPIAppSingleton:
|
25
|
+
"""线程安全的FastAPI应用单例类"""
|
26
|
+
|
27
|
+
_instance = None
|
28
|
+
_lock = threading.Lock()
|
29
|
+
|
30
|
+
def __new__(cls):
|
31
|
+
if cls._instance is None:
|
32
|
+
with cls._lock:
|
33
|
+
# 双重检查锁定模式
|
34
|
+
if cls._instance is None:
|
35
|
+
cls._instance = cls._create_app()
|
36
|
+
return cls._instance
|
37
|
+
|
38
|
+
@classmethod
|
39
|
+
def _create_app(cls):
|
40
|
+
"""创建FastAPI应用实例"""
|
41
|
+
# 创建FastAPI应用实例
|
42
|
+
configs = DefaultSettings()
|
43
|
+
app = FastAPI(
|
44
|
+
title=configs.PROJECT_NAME,
|
45
|
+
version=configs.VERSION,
|
46
|
+
debug=configs.DEBUG,
|
47
|
+
lifespan=lifespan,
|
48
|
+
docs_url=None,
|
49
|
+
redoc_url=None,
|
50
|
+
)
|
51
|
+
|
52
|
+
# 添加静态文件服务器
|
53
|
+
try:
|
54
|
+
import os
|
55
|
+
|
56
|
+
static_dir = os.path.join(os.path.dirname(__file__), "..", "..", "statics")
|
57
|
+
app.mount("/static", StaticFiles(directory=static_dir), name="static")
|
58
|
+
except Exception as e:
|
59
|
+
console.print(f"静态文件服务器启动失败: {e}")
|
60
|
+
|
61
|
+
# 添加路由
|
62
|
+
routes = RoutesDiscover().discover()
|
63
|
+
for route in routes:
|
64
|
+
app.include_router(route)
|
65
|
+
|
66
|
+
return app
|
67
|
+
|
68
|
+
|
69
|
+
app = FastAPIAppSingleton()
|
70
|
+
|
71
|
+
|
72
|
+
class FastApiOperations(CommandBase):
|
73
|
+
def __init__(self, host: str = None, port: int = None):
|
74
|
+
configs = DefaultSettings()
|
75
|
+
self.host = host or configs.HOST
|
76
|
+
self.port = port or configs.PORT
|
77
|
+
self.configs = configs
|
78
|
+
|
79
|
+
def start(self):
|
80
|
+
# 启动服务
|
81
|
+
reload = True if self.configs.DEBUG else False
|
82
|
+
uvicorn.run(
|
83
|
+
"faster_app.commands.builtins.fastapi:app",
|
84
|
+
host=self.host,
|
85
|
+
port=self.port,
|
86
|
+
reload=reload,
|
87
|
+
)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
"""
|
2
|
+
自动发现 apps 目录下的 commands 模块和内置命令
|
3
|
+
"""
|
4
|
+
|
5
|
+
from faster_app.commands.base import CommandBase
|
6
|
+
from faster_app.base import DiscoverBase
|
7
|
+
|
8
|
+
|
9
|
+
class CommandDiscover(DiscoverBase):
|
10
|
+
INSTANCE_TYPE = CommandBase
|
11
|
+
TARGETS = [
|
12
|
+
{
|
13
|
+
"directory": "apps",
|
14
|
+
"filename": "commands.py",
|
15
|
+
"skip_dirs": ["__pycache__"],
|
16
|
+
"skip_files": [],
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"directory": "commands/builtins",
|
20
|
+
"filename": None,
|
21
|
+
"skip_dirs": ["__pycache__"],
|
22
|
+
"skip_files": [],
|
23
|
+
},
|
24
|
+
]
|
faster_app/db.py
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
from tortoise import Tortoise
|
2
|
+
from faster_app.models.discover import ModelDiscover
|
3
|
+
|
4
|
+
|
5
|
+
async def tortoise_init(tortoise_config: dict = None):
|
6
|
+
"""
|
7
|
+
初始化Tortoise ORM
|
8
|
+
|
9
|
+
Args:
|
10
|
+
tortoise_config: Tortoise ORM 配置字典,如果不提供则使用默认配置
|
11
|
+
"""
|
12
|
+
if not Tortoise._inited:
|
13
|
+
if tortoise_config is None:
|
14
|
+
# 提供一个默认的配置示例
|
15
|
+
tortoise_config = {
|
16
|
+
"connections": {"default": "sqlite://db.sqlite3"},
|
17
|
+
"apps": {},
|
18
|
+
"use_tz": False,
|
19
|
+
"timezone": "UTC",
|
20
|
+
}
|
21
|
+
|
22
|
+
# 自动发现模型并添加到配置中
|
23
|
+
apps_models = ModelDiscover().discover()
|
24
|
+
|
25
|
+
# 为每个app创建配置
|
26
|
+
for app_name, models in apps_models.items():
|
27
|
+
tortoise_config["apps"][app_name] = {
|
28
|
+
"models": models,
|
29
|
+
"default_connection": "default",
|
30
|
+
}
|
31
|
+
|
32
|
+
await Tortoise.init(config=tortoise_config)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
"""
|
2
|
+
数据库模型模块
|
3
|
+
|
4
|
+
提供了基于 Tortoise ORM 的模型基类和自动发现功能
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .base import (
|
8
|
+
UUIDModel,
|
9
|
+
DateTimeModel,
|
10
|
+
StatusModel,
|
11
|
+
ScopeModel,
|
12
|
+
)
|
13
|
+
from .discover import ModelDiscover
|
14
|
+
|
15
|
+
__all__ = [
|
16
|
+
"UUIDModel",
|
17
|
+
"DateTimeModel",
|
18
|
+
"StatusModel",
|
19
|
+
"ScopeModel",
|
20
|
+
"ModelDiscover",
|
21
|
+
]
|