Repository navigation
fix(migrations): keep fields whose source_field matches a field name in CreateModel - #2303
belomaxorka wants to merge 1 commit into
Conversation
…in CreateModel The writer skipped every CreateModel field whose name appeared as some field's source_field. That was meant to drop the generated "<fk>_id" backing field of a ForeignKeyField, but it also dropped any field with source_field equal to its own name (e.g. id = BigIntField(primary_key=True, source_field="id")). The next makemigrations then added those fields back and dropped/re-added the primary key, which on PostgreSQL left it without a sequence. Skip only the "<name>_id" backing fields of ForeignKeyField/OneToOneField fields instead.
|
Thanks for the fix — the issue with However, I have a concern about the new approach of skipping The backing field of a FK is generated as Example: With the new logic, Could you clarify how backing fields are identified elsewhere in the codebase? If there's a reliable way to tell a generated backing field apart from a user-defined field, using that would be safer. Otherwise, at minimum, the test coverage should include:
Also, does |
Description
MigrationWriter._format_create_model()skipped every field whose name showed up as some field'ssource_field. The intent was to drop the generated<fk>_idbacking field of aForeignKeyField, butsource_fieldis just the column name, so a field likematched itself and was left out of
CreateModel. In #2251 every field of the abstract base declaressource_field="<own name>", so they all went missing. Inheritance itself isn't involved: the same thing happens on a plain model.The writer now skips only the
<name>_idbacking fields ofForeignKeyField/OneToOneFieldfields in the operation, which is howApps._init_relations()names them. A model can't declare its own field with that name (add_fieldraises on duplicates), so nothing legitimate is dropped.test_writer_excludes_fk_source_fieldstill passes unchanged.Motivation and Context
Fixes #2251.
With the old writer the first
makemigrationsproduced aCreateModelwithout those fields. Since there was no PK, the model got the defaultid IntField. The second run then emittedRemoveField('id')+AddField('id', BigIntField(...))+AddFieldfor the rest. On PostgreSQL that drops theSERIALcolumn and adds"id" BIGINT NOT NULL PRIMARY KEYwithout a sequence, which is the "PK not generated" part of the issue. With the fix the initial migration creates"id" BIGSERIAL NOT NULL PRIMARY KEY, and a second run reports no changes.The
auto_now/auto_now_addpart of the issue is not a bug. Since #2104 those flags are Python-side only and emit noDEFAULT, ingenerate_schemas()too.db_default=Now()is the database-level option.Migrations that were already generated with the old writer are not rewritten, so tables created through them keep the column without a sequence.
Related: #2195 fixes the same filter for PK fields only (for #2176). This is the more general version suggested in that PR's review. It sidesteps the
test_writer_excludes_fk_source_fieldconflict mentioned there by recognising the backing field by name instead of bysource_field. Thegenerated=Falseserialization part of #2195 is not touched here.How Has This Been Tested?
test_writer_keeps_fields_with_own_source_field: writer output keeps a PK and a non-PK field whosesource_fieldequals the field name.test_autodetector_keeps_fields_with_own_source_field: uses the model shape from the issue (abstract base withsource_fieldfields). It writes the initial migration and checks that a second autodetector run finds no changes. It also renders the migration with the PostgreSQL schema editor (fake client) and checks for"id" BIGSERIAL NOT NULL PRIMARY KEY.developand pass with the fix.examples/comprehensive_migrations_projectgives identical output before and after.ruff format --check,ruff check,banditandcodespellare clean.mypyreports the same 2 errors as ondevelop, in files not touched here.Checklist: