modify: config sqlite 配置规范

This commit is contained in:
2026-01-31 19:26:28 +08:00
parent ee899b2eb3
commit f7dbe571cc
5 changed files with 2158 additions and 147 deletions
@@ -1,135 +1,198 @@
"""
配置管理模块
配置管理模块 - 简化版本
基于 Pydantic Settings 和 TOML 文件
"""
from typing import Optional, Dict, Any
from typing import Optional, List, Dict, Any
from pydantic_settings import BaseSettings
from pydantic import Field
from pydantic import model_validator
import toml
from pathlib import Path
import sys
import os
try:
from ...utils.launch import args
except:
from utils.launch import args # type: ignore
from utils.launch import args # type: ignore
class SQLiteConfig(BaseSettings):
"""SQLite 配置"""
engine: str = "tortoise.backends.sqlite"
file_path: str = "db.sqlite3"
journal_mode: str = "WAL"
busy_timeout: int = 10000
maxsize: int = 10
minsize: int = 1
cache_size: int = -2000
synchronous: str = "NORMAL"
temp_store: str = "MEMORY"
mmap_size: int = 1073741824
foreign_keys: bool = True
auto_vacuum: str = "INCREMENTAL"
max_cached_statements: int = 100
readonly: bool = False
@property
def tortoise_config(self) -> Dict[str, Any]:
return {
"default": {
"engine": self.engine,
"credentials": {
"file_path": self.file_path,
"journal_mode": self.journal_mode,
"busy_timeout": self.busy_timeout,
"maxsize": self.maxsize,
"minsize": self.minsize,
"cache_size": self.cache_size,
"synchronous": self.synchronous,
"temp_store": self.temp_store,
"mmap_size": self.mmap_size,
"foreign_keys": self.foreign_keys,
"auto_vacuum": self.auto_vacuum,
"max_cached_statements": self.max_cached_statements,
"readonly": self.readonly,
},
}
}
class Settings(BaseSettings):
"""应用配置"""
# 应用信息
app_name: str = "FastAPI Demo"
app_version: str = "1.0.0"
description: str = "FastAPI 应用"
# 服务器配置
host: str = "0.0.0.0"
port: int = 8000
reload: bool = False
workers: int = 4
# 数据库配置
database_url: str = "sqlite://db.sqlite3"
generate_schemas: bool = False
workers: int = 1 # 开发环境默认1,避免与 reload 冲突
database_type: str = "sqlite"
# SQLite 配置
sqlite_config: SQLiteConfig = SQLiteConfig()
# 环境配置
env: str = "development"
debug: bool = False
# 数据库配置
generate_schemas: bool = False
# 日志配置
logging_level: str = "INFO"
logging_file: Optional[str] = None
# CORS 配置
cors_allow_origins: list = ["*"]
cors_allow_origins: List[str] = ["*"]
cors_allow_credentials: bool = True
cors_allow_methods: list = ["*"]
cors_allow_headers: list = ["*"]
cors_allow_methods: List[str] = ["*"]
cors_allow_headers: List[str] = ["*"]
# 安全配置
secret_key: str = "your-secret-key-change-in-production"
algorithm: str = "HS256"
access_token_expire_minutes: int = 30
# 模块系统
module_system_type: str = "local"
module_system_path: list = ["plugins", "app"]
module_system_path: List[str] = ["plugins", "app"]
class Config:
env_file = ".env"
extra = "ignore"
@model_validator(mode="after")
def validate_settings(self):
"""验证和调整设置"""
# 如果启用 reload,workers 必须为 1
if self.reload and self.workers != 1:
print(f"⚠️ reload 启用,将 workers 从 {self.workers} 调整为 1")
self.workers = 1
return self
@classmethod
def from_toml(cls, config_path: Optional[str] = None) -> "Settings":
"""从 TOML 文件加载配置"""
"""从 TOML 文件加载配置 - 简化版本"""
# 1. 确定配置文件路径
if config_path is None:
# 尝试多个可能的配置路径
possible_paths = [
"config.toml",
"./config.toml",
"../config.toml",
Path(__file__).parent.parent.parent / "config.toml",
]
for path in possible_paths:
if Path(path).exists():
config_path = str(path)
print(f"📄 加载配置文件: {config_path}")
break
if config_path is None:
print("⚠️ 未找到配置文件,使用默认配置")
return cls()
config_path = "config.toml"
config_file = Path(config_path)
if not config_file.exists():
print(f"⚠️ 配置文件不存在: {config_path},使用默认配置")
return cls()
try:
config_file = Path(config_path)
if not config_file.exists():
print(f"⚠️ 配置文件不存在: {config_path}")
return cls()
# 2. 加载 TOML 文件
config_data = toml.load(config_file)
# 获取默认配置
print(f"📄 加载配置文件: {config_path}")
# 3. 确定环境
default_config = config_data.get("default", {})
# 确定环境
env = default_config.get("env", "development")
# 获取环境特定配置
env_config = config_data.get(env, {})
# 合并配置
merged_config = {**default_config, **env_config}
# 处理嵌套配置
for section in ["server", "database", "security", "logging", "cors", "module_system"]:
if section in config_data:
if isinstance(config_data[section], dict):
merged_config.update(config_data[section])
# 从环境特定配置中覆盖
for section in ["server", "database", "security", "logging", "cors", "module_system"]:
env_section_key = f"{env}.{section}"
if env_section_key in config_data:
if isinstance(config_data[env_section_key], dict):
merged_config.update(config_data[env_section_key])
print(f"🌍 环境: {env}")
return cls(**merged_config)
# 4. 获取环境特定配置
env_config = config_data.get(env, {})
# 5. 构建配置字典
config_dict = {}
# 5.1 处理默认配置
for key, value in default_config.items():
if key.startswith("app."):
config_dict[key.replace("app.", "app_")] = value
elif key.startswith("server."):
config_dict[key.replace("server.", "")] = value
elif key == "env":
config_dict["env"] = value
# 5.2 处理环境特定配置
for key, value in env_config.items():
if key.startswith("server."):
config_dict[key.replace("server.", "")] = value
elif key == "debug":
config_dict["debug"] = value
# 5.3 处理 database 配置
database_config = {}
if "database" in env_config:
database_type = env_config["database"].get("type", "sqlite")
database_config = env_config["database"].get(database_type, {})
config_dict["database_type"] = database_type
# 5.4 处理 generate_schemas
if "database" in env_config:
db_config = env_config["database"]
if isinstance(db_config, dict) and "generate_schemas" in db_config:
config_dict["generate_schemas"] = db_config["generate_schemas"]
if database_type == "sqlite":
if database_config:
config_dict["sqlite_config"] = SQLiteConfig(**database_config)
return cls(**config_dict)
except Exception as e:
print(f"❌ 加载配置失败: {e}")
import traceback
traceback.print_exc()
return cls()
# 全局配置实例
_settings = None
def get_settings() -> Settings:
"""获取配置实例(单例模式)"""
global _settings
if _settings is None:
_settings = Settings.from_toml(args.config)
return _settings
return _settings
@@ -1,19 +1,21 @@
"""
Tortoise-ORM 数据库配置
"""
from typing import Optional
from tortoise import Tortoise
from tortoise.contrib.fastapi import register_tortoise
from .config import get_settings
settings = get_settings()
async def init_db(run_mode: str):
"""初始化数据库连接"""
settings = get_settings()
db_config = getattr(settings, f"{settings.database_type}_config").tortoise_config
if run_mode == "production":
db_config = {
"connections": {
"default": settings.database_url
},
"connections": db_config,
"apps": {
"models": {
"models": ["app.models", "aerich.models"],
@@ -23,11 +25,10 @@ async def init_db(run_mode: str):
"use_tz": False,
"timezone": "UTC",
}
elif run_mode == "development":
db_config = {
"connections": {
"default": settings.database_url
},
"connections": db_config,
"apps": {
"models": {
"models": ["{{ cookiecutter.project_name }}.app.models", "aerich.models"],
@@ -39,9 +40,9 @@ async def init_db(run_mode: str):
}
else:
raise ValueError("Invalid run mode")
await Tortoise.init(db_config)
# 根据配置决定是否生成表结构
if settings.generate_schemas:
print("🗃️ 生成数据库表结构...")
@@ -49,41 +50,44 @@ async def init_db(run_mode: str):
print("✅ 数据库表结构生成完成")
else:
print("⏭️ 跳过数据库表结构生成(建议使用迁移工具)")
print(f"✅ 数据库连接成功: {settings.database_url}")
print(f"✅ 数据库连接成功: {db_config}")
async def close_db():
"""关闭数据库连接"""
await Tortoise.close_connections()
print("✅ 数据库连接已关闭")
def register_db(app, run_mode: str):
"""将数据库注册到 FastAPI 应用"""
settings = get_settings()
modules_path = "app.models" if run_mode == "production" else "{{ cookiecutter.project_name }}.app.models"
modules_path = "app.models" if run_mode == "production" else "{{ cookiecutter.project_name }}.app.models"
file_path = getattr(settings, f"{settings.database_type}_config").file_path
register_tortoise(
app,
db_url=settings.database_url,
db_url=f"sqlite://{file_path}",
modules={"models": [modules_path]},
generate_schemas=settings.generate_schemas,
add_exception_handlers=True,
)
return app
# 在 app/core/database.py 中添加
from aerich import Command
async def run_migrations():
"""运行数据库迁移"""
try:
command = Command(
tortoise_config={
"connections": {
"default": get_settings().database_url
},
"connections": getattr(
settings, f"{settings.database_type}_config"
).tortoise_config,
"apps": {
"models": {
"models": ["app.models", "aerich.models"],
@@ -91,13 +95,12 @@ async def run_migrations():
}
},
},
app="models"
app="models",
)
# 检查并应用迁移
await command.init()
await command.upgrade()
print("✅ 数据库迁移完成")
except Exception as e:
print(f"⚠️ 数据库迁移失败: {e}")