Files
crm_project/server/alembic/env.py
T
hankin 815cbf9d8c v0.2.0: CRM/ERP 系统升级 - 清理 .gitignore 并移除误提交的 venv/env/db 文件
- 更新 .gitignore:全面覆盖环境变量、数据库、日志、缓存、上传文件
- 移除误跟踪的 server/venv/、crm_data.db、.env 文件
- 新增 server/.env.example 模板
- 新增合同管理、利润核算、AI教练等功能模块
- 新增 Playwright e2e 测试套件
- 前后端多项功能升级和 bug 修复
2026-05-11 07:24:19 +00:00

99 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Alembic env.py — 异步 PostgreSQL 迁移环境
从 .env 读取 DATABASE_URL,自动发现项目所有 ORM 模型
"""
import asyncio
import os
import sys
from logging.config import fileConfig
from alembic import context
from dotenv import load_dotenv
from sqlalchemy import pool
from sqlalchemy.ext.asyncio import async_engine_from_config
# 确保项目根目录在 sys.path 中
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
# 加载 .env
load_dotenv(os.path.join(os.path.dirname(os.path.dirname(__file__)), ".env"))
# Alembic Config
config = context.config
# 从 .env 动态设置 sqlalchemy.urlasyncpg → psycopg2 用于迁移)
db_url = os.getenv("DATABASE_URL", "")
# Alembic 需要同步驱动,将 asyncpg 替换为 psycopg2
sync_url = db_url.replace("+asyncpg", "")
# 宿主机执行 Alembic 时,host.docker.internal 不可达,替换为回环地址
sync_url = sync_url.replace("host.docker.internal", "127.0.0.1")
# configparser 把 % 当插值语法,需要转义为 %%
config.set_main_option("sqlalchemy.url", sync_url.replace("%", "%%"))
# 日志配置
if config.config_file_name is not None:
fileConfig(config.config_file_name)
# 导入所有模型,确保 Alembic 能检测到所有表
from app.models.base import Base
from app.models import crm, erp, order, shipping, finance, ai, sys as sys_models, contract, cost
target_metadata = Base.metadata
def run_migrations_offline() -> None:
"""离线迁移(仅生成 SQL 脚本)"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def do_run_migrations(connection):
context.configure(connection=connection, target_metadata=target_metadata)
with context.begin_transaction():
context.run_migrations()
async def run_async_migrations():
"""在线迁移(异步引擎)"""
from sqlalchemy.ext.asyncio import create_async_engine
# 宿主机执行 Alembic 时,host.docker.internal 不可达,替换为回环地址
async_url = os.getenv("DATABASE_URL", "").replace("host.docker.internal", "127.0.0.1")
connectable = create_async_engine(
async_url,
poolclass=pool.NullPool,
)
async with connectable.connect() as connection:
await connection.run_sync(do_run_migrations)
await connectable.dispose()
def run_migrations_online() -> None:
"""在线迁移入口"""
# 如果是 asyncpg 则走异步迁移
db_url = os.getenv("DATABASE_URL", "")
if "asyncpg" in db_url:
asyncio.run(run_async_migrations())
else:
from sqlalchemy import engine_from_config
connectable = engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
do_run_migrations(connection)
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()