Skip to content

use_alter 在 Alembic autogenerate 下会静默丢失循环外键 #540

Closed

Description

@Echo-Note

背景

sys_user.dept_id → sys_dept.id 与 sys_dept 的审计字段(created_id/updated_id/deleted_id → sys_user.id,来自 UserMixin)构成循环外键。

当前 dev 分支通过给 dept_id 加 use_alter=True 规避该循环(backend/app/modules/system/user/model.py:84)。

问题

use_alter 在 create_all 建表场景下没问题,但一旦项目引入 Alembic 迁移(autogenerate),会静默丢失外键:

  1. autogenerate 生成基线迁移时,会把 use_alter=True 的约束内联进 op.create_table,而不是拆成独立的 op.create_foreign_key;
  2. 执行 op.create_table 时,PostgreSQL 方言编译 CREATE TABLE 会跳过 use_alter 约束(它预期该约束由后续 ALTER 单独发出);
  3. 但 op.create_table 不会像 MetaData.create_all 那样补发 ALTER,于是 sys_user.dept_id 外键被静默丢失。

已在 PostgreSQL 实测复现:op.create_table 后 inspect.get_foreign_keys("sys_user") 返回空,且 alembic check 会报模型与库不一致。

建议

与其用 use_alter 标记循环边,不如消除循环根源:去掉 UserMixin 三个审计字段(created_id/updated_id/deleted_id)指向 sys_user 的数据库级外键约束(ondelete=SET NULL 已允许悬空,审计字段本就不需要强引用语义),created_by/updated_by/deleted_by 关系改用显式 primaryjoin 保持可查。

这样循环依赖消失,autogenerate 无需 use_alter 即可正确生成迁移。已在 fork 上验证(pytest 74 passed)。

若该方向可行,我可基于 dev 分支提交对应 PR(改动 base_model.py 与 modules/system/user/model.py)。

Activity

  1. fastapiadmin commented on Oct 22, 2026

    @fastapiadmin
    Owner

    已修复并合并到 dev:PR #541(合并提交 45a8ade9)。

    验证要点:

    • sys_dept 只剩 parent_id 自引用外键、sys_user 只剩 dept_id → 循环外键消除
    • created_by/updated_by/deleted_by 改用显式 primaryjoin,local/remote pairs = 表.created_id → sys_user.id,selectinload 可正常执行
    • ruff / basedpyright 0 errors / pytest 97 passed

    后续项(不阻塞):仓库 Alembic 目前只有 env.py 无版本,线上既有库仍带旧外键;将来引入基线迁移时需补一条 drop_constraint。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions