#37351: Altering the null attribute of a GeneratedField should raise when making
migrations
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: 6.1
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Natalia Bidart):
* stage: Unreviewed => Accepted
Comment:
Thanks Jacob. I agree the current behavior is a bug, so I'll Accept on
that basis. But I have concerns about raising if
`modifying_generated_field` holds:
1. The proposed check is in the schema editor, therefore `makemigrations`
still generates the `AlterField` which is conceptually incorrect.
2. (Arguably worse) The error surfaces on `migrate`, which is "too late":
people who already have such an `AlterField` in their migration history
would need to edit it, and a deploy is a bad moment to find that out.
3. Now that we merged the revert of W225 in #37348, users who removed
`null=True` to silence W225 need to add it back. Making a generated column
nullable again is just dropping the NOT NULL constraint (ish), but under
this proposal I think Django would refuse that and tell users to drop the
column and add it again, which for a stored column means recomputing every
row, and loses any untracked index or constraint.
4. This proposal is very backward incompatible, since existing
`AlterField` migrations changing `null` on generated fields have been
applied successfully (when nullable or without NULL rows). Raising now
would break migrating those projects (fully functional now) from scratch,
including test databases.
So I think the root issue is that column creation and alteration disagree:
`_iter_column_sql()` never emits `NOT NULL` for a generated column given
this guards:
{{{#!python
if field.generated:
generated_sql, generated_params =
self._column_generated_sql(field)
params.extend(generated_params)
yield generated_sql
elif not null:
yield "NOT NULL"
}}}
while `_alter_field()` does. That's also why the suggested workaround
doesn't help, since removing and re-adding the field produces a nullable
column no matter what `null` says. So the question to settle first is
whether `null` should affect the DDL of a `GeneratedField`:
* If it shouldn't, the alteration should be skipped for generated fields
which matches creation.
* If it should, creation needs to emit `NOT NULL` as well.
--
Ticket URL: <
https://code.djangoproject.com/ticket/37351#comment:2>