django-safe-migration
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDjango Migration — Zero Downtime
Django 迁移 — 零停机
Project Configuration
项目配置
Read the active host's project instruction file (for example, or
) for the values below. If they are not set, use the defaults shown.
AGENTS.mdCLAUDE.md| Key | Default | Notes |
|---|---|---|
| Django version | unknown | Affects |
| Deploy strategy | rolling deploy | Rolling deploy is the most restrictive; blue/green or maintenance-window deploys allow more operations |
| Runtime guard | none | If a guard is configured (e.g. |
| Migration command | | e.g. |
| Docs / wiki URL | none | If set, append |
To configure this skill for your project, add a section like this to the active
host's project instruction file:
undefined请读取当前宿主的项目说明文件(例如 或 )获取以下配置值。如果未设置,则使用所示的默认值。
AGENTS.mdCLAUDE.md| 配置项 | 默认值 | 说明 |
|---|---|---|
| Django 版本 | unknown | 影响 |
| 部署策略 | rolling deploy | 滚动部署限制最严格;蓝绿部署或维护窗口部署允许更多操作 |
| 运行时防护 | none | 如果配置了防护工具(例如 |
| 迁移命令 | | 例如 |
| 文档/维基 URL | none | 如果已设置,在审查输出中标记问题时需附加 |
要为你的项目配置此技能,请将以下类似内容添加到当前宿主的项目说明文件中:
undefineddjango-safe-migration
django-safe-migration
- Django version: 5.1
- Deploy strategy: rolling deploy
- Runtime guard: none
- Migration command: docker compose run web python manage.py sqlmigrate
- Docs URL: https://github.com/your-org/repo/wiki/migrations
---- Django version: 5.1
- Deploy strategy: rolling deploy
- Runtime guard: none
- Migration command: docker compose run web python manage.py sqlmigrate
- Docs URL: https://github.com/your-org/repo/wiki/migrations
---When to Use
适用场景
- "Review this migration"
- "Is this migration safe?"
- "Write a migration for..."
- "Rewrite this migration to be safe"
- "How do I add a NOT NULL column / drop a column / add an index / rename a column / add a FK..."
- “审查这个迁移”
- “这个迁移安全吗?”
- “为…编写迁移”
- “将此迁移重写为安全版本”
- “如何添加NOT NULL列/删除列/添加索引/重命名列/添加FK…”
Why Zero-Downtime Migrations Matter
为什么零停机迁移很重要
In a rolling deploy, the new database schema is applied first, then application instances are restarted one by one. At any moment during the deploy, old code and new code run simultaneously against the same database.
Every migration must be safe to run while the previous version of the app is still serving traffic. A migration that takes an lock on a large table blocks all reads and writes — downtime even for a few seconds on a busy table.
ACCESS EXCLUSIVEThe problem is not just the lock itself but the wait queue: a fast that takes 50ms will queue behind any long-running transaction, and all subsequent queries queue behind the migration. On a busy table this cascades into connection pool exhaustion.
ALTER TABLE在滚动部署中,首先应用新的数据库schema,然后逐个重启应用实例。在部署期间的任何时刻,旧代码和新代码都会同时针对同一个数据库运行。
在应用的旧版本仍在处理流量时,每个迁移都必须能够安全运行。对大表加 锁的迁移会阻塞所有读写操作——即便只有几秒钟,对于繁忙的表来说也意味着停机。
ACCESS EXCLUSIVE问题不仅仅在于锁本身,还在于等待队列:一个耗时50毫秒的快速 操作会排在任何长事务之后,而所有后续查询又会排在迁移之后。在繁忙的表上,这会级联导致连接池耗尽。
ALTER TABLEHow PostgreSQL Locking Works
PostgreSQL 锁机制原理
| Lock | Acquired by | Blocks |
|---|---|---|
| Most | All reads and writes |
| | Writes only (on both tables) |
| | Writes only |
| | Nothing meaningful — safe under traffic |
For the full conflict matrix (table-level locks × business logic operations × row-level locks) and the FIFO wait-queue explanation, load . Load it when:
references/postgres-locks.md- explaining why a specific operation is unsafe
- a developer asks what a lock type blocks or conflicts with
- reasoning about whether two concurrent operations interact
| 锁类型 | 触发操作 | 阻塞内容 |
|---|---|---|
| 大多数 | 所有读写操作 |
| | 仅写操作(两张表均受影响) |
| | 仅写操作 |
| | 无实质阻塞——流量下安全 |
完整的冲突矩阵(表级锁 × 业务逻辑操作 × 行级锁)以及FIFO等待队列的说明,请加载 。在以下场景加载该文件:
references/postgres-locks.md- 解释某个特定操作为什么不安全时
- 开发者询问某类锁会阻塞或与什么冲突时
- 推断两个并发操作是否会相互影响时
lock_timeout
lock_timeout
Any operation that requires should be preceded by . This causes the migration to fail fast (with a clear error) instead of waiting indefinitely for the lock — preventing connection pool exhaustion from queue cascading.
ACCESS EXCLUSIVESET LOCAL lock_timeoutFor a normal transactional migration:
python
migrations.RunSQL("SET LOCAL lock_timeout = '2s'"),
migrations.AlterField(...), # or any ACCESS EXCLUSIVE operationSET LOCALDefault: — adjust up if the table is known to have long-running transactions that legitimately need more time, or down for stricter environments.
2sFor migrations, combine and the DDL in the same operation; see Structural Rules below.
atomic = FalseSET LOCALRunSQL任何需要 锁的操作都应该在之前执行 。这会让迁移快速失败(并返回明确的错误),而不是无限期等待锁——从而防止队列级联导致的连接池耗尽。
ACCESS EXCLUSIVESET LOCAL lock_timeout对于普通的事务性迁移:
python
migrations.RunSQL("SET LOCAL lock_timeout = '2s'"),
migrations.AlterField(...), # or any ACCESS EXCLUSIVE operationSET LOCAL默认值:——如果已知表上存在确实需要更多时间的长事务,可以调大该值;对于更严格的环境,可以调小。
2s对于 的迁移,请将 和DDL操作合并在同一个 操作中;参见下文的结构规则。
atomic = FalseSET LOCALRunSQLKey Patterns
核心模式
NOT VALID + VALIDATE (for FK and CHECK constraints)
NOT VALID + VALIDATE(适用于FK和CHECK约束)
A two-step PostgreSQL technique to add a constraint without a long lock:
- — creates the constraint and enforces it on new writes immediately, but skips scanning existing rows. Takes a brief lock with no table scan —
ADD CONSTRAINT … NOT VALIDon both tables for FK constraints,SHARE ROW EXCLUSIVEfor CHECK constraints.ACCESS EXCLUSIVE - — scans existing rows to confirm they satisfy the constraint. Takes
VALIDATE CONSTRAINT(plusSHARE UPDATE EXCLUSIVEon the referenced table for FK constraints), which does not block reads or writes.ROW SHARE
The dangerous part is the full-table scan, not the constraint creation itself. Splitting it keeps the write-blocking lock window to milliseconds, with the long scan moved to a non-blocking step.
PostgreSQL docs: ·
NOT VALIDVALIDATE CONSTRAINT这是PostgreSQL的一种分两步添加约束的技术,可避免长时间加锁:
- — 创建约束并立即对新写入强制执行,但跳过扫描现有行。仅需短暂加锁,无需全表扫描——FK约束会在两张表上加
ADD CONSTRAINT … NOT VALID锁,CHECK约束则加SHARE ROW EXCLUSIVE锁。ACCESS EXCLUSIVE - — 扫描现有行以确认它们满足约束。仅需
VALIDATE CONSTRAINT锁(对于FK约束,还会在被引用表上加SHARE UPDATE EXCLUSIVE锁),不会阻塞读写操作。ROW SHARE
危险的部分是全表扫描,而不是约束创建本身。拆分后,阻塞写操作的锁窗口被缩短到毫秒级,而耗时较长的扫描被移到了非阻塞步骤中。
PostgreSQL 文档: ·
NOT VALIDVALIDATE CONSTRAINTRuntime Guards
运行时防护工具
Some projects configure a custom database backend or linter that raises errors for unsafe operations at migration time (e.g. , , ).
zero_downtime_migrationsdjango-pg-zero-downtime-migrationsdjango-migration-linterWhen reviewing a migration:
- Operations the project's runtime guard blocks → classify as Error (migration will not run)
- Operations the guard does not cover → classify as Warning (migration runs but may cause downtime)
If no runtime guard is configured, treat all unsafe operations as Errors that require a safe rewrite before deploying to production.
Check the Project Configuration block above (or ) for what this project's guard covers.
AGENTS.md有些项目会配置自定义数据库后端或检查工具,在迁移时对不安全的操作抛出错误(例如 、、)。
zero_downtime_migrationsdjango-pg-zero-downtime-migrationsdjango-migration-linter审查迁移时:
- 项目运行时防护工具阻止的操作 → 归类为错误(迁移无法运行)
- 防护工具未覆盖的操作 → 归类为警告(迁移可以运行,但可能导致停机)
如果未配置运行时防护工具,将所有不安全的操作都视为错误,需要在部署到生产环境前进行安全重写。
请查看上方的项目配置模块(或 ),了解此项目的防护工具覆盖范围。
AGENTS.mdMode 1: Review
模式1:审查
Goal
目标
Identify every operation that is unsafe or risky for a rolling deploy on PostgreSQL.
找出在PostgreSQL上进行滚动部署时所有不安全或有风险的操作。
Steps
步骤
- Read the migration file in full.
- Run to get the actual SQL Django will execute. Always do this — the generated SQL is the ground truth. Use the
<migration_command> <app_label> <migration_name>value from the active host's project instruction file; default isMigration command. If the key is not set and apython manage.py sqlmigrateorMakefileexists in the project root, ask the user: "How do you run sqlmigrate in this project?" and suggest they save the answer to that instruction file. The ORM operation class alone is not sufficient: for example,docker-compose.ymlon a FK field that addsAlterFieldalso drops and re-adds the FK constraint, emittingnull=True(takingDROP CONSTRAINTon both the child and referenced table) followed byACCESS EXCLUSIVEwithoutADD CONSTRAINT FOREIGN KEY(takingNOT VALIDwith a full scan on both tables) — neither is visible from the migration file alone.SHARE ROW EXCLUSIVE - Load . Load
references/operation-guide.mdwhen explaining why a flagged operation is unsafe.references/postgres-locks.md - For each SQL statement produced, check it against the detection checklist below.
- If any operation requires (flagged as error or warning), ask the user before outputting the report:
ACCESS EXCLUSIVE"This migration contains anoperation. AACCESS EXCLUSIVEshould be added to fail fast instead of queuing and cascading. The default islock_timeout— confirm or provide a custom value." If the migration already contains2s, note the existing value and ask the user to confirm it is appropriate. Use the confirmed value in the fix instructions.SET LOCAL lock_timeout - Output a structured report:
- 完整读取迁移文件。
- 运行 获取Django实际执行的SQL。务必执行此步骤——生成的SQL是最终依据。 请使用当前宿主项目说明文件中的
<migration_command> <app_label> <migration_name>值;默认值为迁移命令。如果未设置该配置项,且项目根目录中存在python manage.py sqlmigrate或Makefile,请询问用户:“你在这个项目中如何运行sqlmigrate?”并建议他们将答案保存到该说明文件中。仅靠ORM操作类是不够的:例如,对FK字段执行docker-compose.yml添加AlterField时,还会删除并重新添加FK约束,生成null=True(对子表和被引用表都加DROP CONSTRAINT锁),随后是不带ACCESS EXCLUSIVE的NOT VALID(对两张表都加ADD CONSTRAINT FOREIGN KEY锁并进行全表扫描)——这两个操作仅从迁移文件中是看不到的。SHARE ROW EXCLUSIVE - 加载 。在解释被标记的操作为什么不安全时,加载
references/operation-guide.md。references/postgres-locks.md - 针对生成的每条SQL语句,对照下方的检测清单进行检查。
- 如果有任何操作需要 锁(标记为错误或警告),在输出报告前询问用户:
ACCESS EXCLUSIVE“此迁移包含操作。应添加ACCESS EXCLUSIVE以实现快速失败,避免队列级联。默认值为lock_timeout——请确认或提供自定义值。” 如果迁移中已经包含2s,请说明现有值并询问用户确认是否合适。 在修复说明中使用确认后的值。SET LOCAL lock_timeout - 输出结构化报告:
Migration Review: <filename>
迁移审查:<filename>
Errors — will cause downtime or be blocked by runtime guard
错误 — 会导致停机或被运行时防护工具阻止
- [ERROR] on
<OperationClass>: <what it does and why it's unsafe> Fix: <one-sentence description of the safe alternative> What this rewrite changes: clarify whether<app>.<Model>.<field>is still required in the safe version, and if so, explain what actually improves — lock duration (full table scan → milliseconds), failure mode (silent queue cascade → fast timeout error), or both. Never let a reader assume the rewrite eliminates the lock entirely. <wiki/docs link if configured>ACCESS EXCLUSIVE
- [错误] 上的
<app>.<Model>.<field>:<操作内容及不安全原因> 修复方案:<安全替代方案的一句话描述> 重写变更说明:说明安全版本中是否仍需要<OperationClass>锁,如果需要,解释实际改进点——锁持续时间(全表扫描 → 毫秒级)、失败模式(静默队列级联 → 快速超时错误),或两者皆有。绝不能让读者误以为重写完全消除了锁。 <如果配置了维基/文档链接,附上>ACCESS EXCLUSIVE
Warnings — may cause extended locks or deployment issues
警告 — 可能导致长时间锁或部署问题
- [WARNING] : <issue> Fix: <safe alternative>
<OperationClass>
- [警告] :<问题> 修复方案:<安全替代方案>
<OperationClass>
Structural Issues
结构问题
- [ERROR|WARNING] <issue> (e.g., missing atomic=False, RunPython without reverse)
- [错误|警告] <问题>(例如缺少 atomic=False、RunPython 没有反向操作)
Safe
安全操作
- [OK] <operations that pass all checks>
- If there are errors or warnings, offer to rewrite (Mode 3).
- If everything passes, confirm the migration is safe to deploy.
- [通过] <通过所有检查的操作>
- 如果存在错误或警告,主动提供重写服务(模式3)。
- 如果所有检查都通过,确认迁移可以安全部署。
Mode 2: Write
模式2:编写
Goal
目标
Generate correct, zero-downtime migration(s) for a described change.
为描述的变更生成正确的零停机迁移。
Steps
步骤
- Load and
references/operation-guide.md.references/examples.md - Clarify the operation if ambiguous:
- What model and field?
- New column or changing an existing one?
- For FK: which table is referenced? New column or existing?
- For type changes: from what type to what type?
- Django version (affects availability)?
db_default
- If the operation will require , ask the user:
ACCESS EXCLUSIVE"This migration will use. AACCESS EXCLUSIVEwill be included to fail fast if the lock cannot be acquired. The default islock_timeout— confirm or provide a custom value."2s - Determine how many migration files are needed — many patterns require two files in separate PRs.
- Generate the migration file(s) using patterns from . Add
references/examples.mdbefore eachSET LOCAL lock_timeout = '<confirmed_value>'statement. In normalACCESS EXCLUSIVEmigrations, this can be a precedingatomic = True; inRunSQLmigrations, combine the timeout and DDL in the sameatomic = Falseoperation soRunSQLis still active when the DDL runs.SET LOCAL - When two files are needed, always output deployment instructions:
undefined- 加载 和
references/operation-guide.md。references/examples.md - 如果操作不明确,先进行澄清:
- 涉及哪个模型和字段?
- 是新列还是修改现有列?
- 对于FK:引用哪张表?是新列还是现有列?
- 对于类型变更:从什么类型改成什么类型?
- Django版本(影响 的可用性)?
db_default
- 如果操作需要 锁,询问用户:
ACCESS EXCLUSIVE“此迁移将使用锁。将包含ACCESS EXCLUSIVE以便在无法获取锁时快速失败。默认值为lock_timeout——请确认或提供自定义值。”2s - 确定需要多少个迁移文件——许多模式需要分两个PR提交两个文件。
- 使用 中的模式生成迁移文件。在每个
references/examples.md语句前添加ACCESS EXCLUSIVE。在普通的SET LOCAL lock_timeout = '<确认后的值>'迁移中,可以用一个前置的atomic = True实现;在RunSQL迁移中,请将超时设置和DDL合并在同一个atomic = False操作中,确保DDL运行时RunSQL仍然生效。SET LOCAL - 如果需要两个文件,始终输出部署说明:
undefinedDeployment Order
Deployment Order
- Migration 1: ships in the same PR as the model/code change
- Migration 2: ships in a follow-up PR after the deploy is confirmed stable
---- Migration 1: ships in the same PR as the model/code change
- Migration 2: ships in a follow-up PR after the deploy is confirmed stable
---Mode 3: Rewrite
模式3:重写
Goal
目标
Transform an existing unsafe migration into one or more safe migrations.
将现有的不安全迁移转换为一个或多个安全迁移。
Steps
步骤
- Read the migration file.
- Identify all unsafe operations using the detection checklist.
- Load and
references/operation-guide.md.references/examples.md - If any operation requires , ask the user:
ACCESS EXCLUSIVE"This migration contains anoperation. AACCESS EXCLUSIVEwill be added to the rewrite to fail fast if the lock cannot be acquired. The default islock_timeout— confirm or provide a custom value."2s - For each unsafe operation, apply the correct safe pattern.
- Add before each
SET LOCAL lock_timeout = '<confirmed_value>'statement in the rewritten migration. In normalACCESS EXCLUSIVEmigrations, this can be a precedingatomic = True; inRunSQLmigrations, combine the timeout and DDL in the sameatomic = Falseoperation soRunSQLis still active when the DDL runs.SET LOCAL - If the rewrite requires splitting into two files, generate both and include deployment instructions.
- Preserve: migration number prefix, , any safe operations unchanged.
dependencies - After rewriting, verify structural rules (see below).
- After the migration code, always output a "What this rewrite changes" block that explains:
- Whether is still required (often yes — be explicit about this).
ACCESS EXCLUSIVE - What actually improves: lock duration (full table scan → milliseconds for metadata-only ops), failure mode (silent queue → fast timeout error with ), or both.
lock_timeout - Any data integrity window introduced (e.g., means existing rows are unvalidated until Migration 2 runs) and whether it matters given the table's prior state.
NOT VALID
- Whether
- 读取迁移文件。
- 使用检测清单找出所有不安全的操作。
- 加载 和
references/operation-guide.md。references/examples.md - 如果有任何操作需要 锁,询问用户:
ACCESS EXCLUSIVE“此迁移包含操作。重写时将添加ACCESS EXCLUSIVE以便在无法获取锁时快速失败。默认值为lock_timeout——请确认或提供自定义值。”2s - 对每个不安全的操作,应用正确的安全模式。
- 在重写后的迁移中,每个 语句前都添加
ACCESS EXCLUSIVE。在普通的SET LOCAL lock_timeout = '<确认后的值>'迁移中,可以用一个前置的atomic = True实现;在RunSQL迁移中,请将超时设置和DDL合并在同一个atomic = False操作中,确保DDL运行时RunSQL仍然生效。SET LOCAL - 如果重写需要拆分为两个文件,生成两个文件并包含部署说明。
- 保留以下内容:迁移编号前缀、、所有安全操作保持不变。
dependencies - 重写完成后,验证结构规则(见下文)。
- 在迁移代码之后,始终输出**“重写变更说明”**模块,解释以下内容:
- 是否仍需要 锁(通常是需要的——请明确说明这一点)。
ACCESS EXCLUSIVE - 实际改进点:锁持续时间(全表扫描 → 仅元数据操作的毫秒级)、失败模式(静默队列 → 带 的快速超时错误),或两者皆有。
lock_timeout - 引入的任何数据完整性窗口(例如 意味着在迁移2运行前,现有行未经过验证),以及考虑到表的先前状态,这是否有影响。
NOT VALID
- 是否仍需要
Detection Checklist
检测清单
Errors — unsafe regardless of runtime guard
错误 — 无论是否有运行时防护都不安全
| Django operation | What to detect | Why it's unsafe |
|---|---|---|
| | Old code inserts omit the column — no DB-level default to fall back on |
| not inside | Old code queries the dropped column by name — crashes immediately |
| not inside | Old code queries the dropped table — crashes immediately |
| not using | |
| not using | |
| not using | Full table scan under |
| not using | Full table scan under |
| removing | Full table scan under |
| | Django drops and re-adds the FK: |
| | CONCURRENTLY cannot run inside a transaction — will error |
| function imports model directly ( | Uses current model class, not historical snapshot — breaks old migrations |
| Django操作 | 检测点 | 不安全原因 |
|---|---|---|
| | 旧代码的插入操作会省略该列——没有数据库级默认值可以兜底 |
| 未包含在 | 旧代码按名称查询已删除的列——会立即崩溃 |
| 未包含在 | 旧代码查询已删除的表——会立即崩溃 |
| 未使用 | |
| 未使用 | |
| 未使用 | 对子表和被引用表都加 |
| 未使用 | 在 |
| 未通过CHECK路径移除现有列的 | 在 |
| | Django会删除并重新添加FK: |
| | CONCURRENTLY 不能在事务内运行——会报错 |
| 函数直接导入模型( | 使用当前模型类而非历史快照——会破坏旧迁移 |
Additional errors if covered by the project's runtime guard
如果项目运行时防护覆盖,需额外标记的错误
If the project has a runtime guard configured (see Project Configuration), also flag these as Errors (they will raise at migration time):
| Django operation | What to detect |
|---|---|
| any rename |
| any rename |
| column type changes |
| |
If no runtime guard is configured, flag these as Errors too — they require a safe rewrite.
如果项目配置了运行时防护工具(见项目配置),也需将以下内容标记为错误(它们会在迁移时抛出异常):
| Django操作 | 检测点 |
|---|---|
| 任何重命名操作 |
| 任何重命名操作 |
| 列类型变更 |
| |
如果未配置运行时防护工具,也需将这些标记为错误——它们需要进行安全重写。
Warnings
警告
| Django operation | What to detect | Issue |
|---|---|---|
| not using index-first pattern | Inline index under |
| adding | Takes |
| missing | Not reversible |
| missing | Not reversible |
| Django操作 | 检测点 | 问题 |
|---|---|---|
| 未使用先建索引模式 | 在 |
| 给现有列添加 | 会加 |
| 缺少 | 不可回滚 |
| 缺少 | 不可回滚 |
Structural Rules (always check)
结构规则(始终检查)
- on the
atomic = Falseclass whenever any operation usesMigrationorCONCURRENTLY. ForVALIDATE CONSTRAINTspecifically: (1)VALIDATE CONSTRAINTis self-conflicting — see the conflict matrix inSHARE UPDATE EXCLUSIVE; (2)references/postgres-locks.mdkeeps the wrapping transaction open for the full scan duration, holding all prior statement locks and increasing deadlock risk; (3)atomic = Truelets VALIDATE run in its own transaction and release locks immediately on completion.atomic = False - split for
SeparateDatabaseAndState/RemoveField: always two separate files.DeleteModel - : always provide
RunPythonat minimum.reverse_code=migrations.RunPython.noop - : always provide
RunSQL. If truly irreversible, usereverse_sqland note why.migrations.RunSQL.noop - Model access in : always
RunPython, never direct imports.apps.get_model("app", "ModelName") - : required before every
SET LOCAL lock_timeoutoperation. Default value isACCESS EXCLUSIVE; always confirm with the user before writing or rewriting. Use2s(notSET LOCAL) so the timeout is scoped to the current transaction.SET- exception:
atomic = Falseonly resets at transaction end. In anSET LOCALmigration, each operation runs outside a wrapping transaction, so a standaloneatomic = Falseresets before the next operation executes and has no effect. When the migration hasmigrations.RunSQL("SET LOCAL lock_timeout = '2s'"), always combine the timeout and the DDL in a singleatomic = Falsecall:RunSQLpythonmigrations.RunSQL(""" SET LOCAL lock_timeout = '2s'; ALTER TABLE app_model ADD COLUMN ...; """)
- 只要有任何操作使用 或
CONCURRENTLY,VALIDATE CONSTRAINT类必须设置Migration。特别是对于atomic = False:(1)VALIDATE CONSTRAINT锁是自冲突的——参见SHARE UPDATE EXCLUSIVE中的冲突矩阵;(2)references/postgres-locks.md会让包装事务在整个扫描期间保持打开状态,持有所有先前语句的锁,增加死锁风险;(3)atomic = True让VALIDATE在自己的事务中运行,完成后立即释放锁。atomic = False - /
RemoveField的DeleteModel拆分:始终分为两个独立文件。SeparateDatabaseAndState - :至少始终提供
RunPython。reverse_code=migrations.RunPython.noop - :始终提供
RunSQL。如果确实不可回滚,使用reverse_sql并说明原因。migrations.RunSQL.noop - 中的模型访问:始终使用
RunPython,绝对不要直接导入。apps.get_model("app", "ModelName") - :每个
SET LOCAL lock_timeout操作前都必须添加。默认值为ACCESS EXCLUSIVE;编写或重写前务必与用户确认。使用2s(而非SET LOCAL),确保超时范围限定在当前事务内。SET- 例外情况:
atomic = False仅在事务结束时重置。在SET LOCAL的迁移中,每个操作都在包装事务之外运行,因此单独的atomic = False会在下一个操作执行前重置,不会生效。当迁移设置了migrations.RunSQL("SET LOCAL lock_timeout = '2s'")时,始终将超时设置和DDL合并在同一个atomic = False调用中:RunSQLpythonmigrations.RunSQL(""" SET LOCAL lock_timeout = '2s'; ALTER TABLE app_model ADD COLUMN ...; """)