Opened 114 minutes ago
Last modified 95 minutes ago
#37208 new Bug
db_persist has problem with postgres
| Reported by: | Twili Spar | Owned by: | |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 6.0 |
| Severity: | Normal | Keywords: | db_persist, GeneratedField |
| Cc: | Twili Spar | Triage Stage: | Unreviewed |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Environment:
Python version: 3.13.3
Django version: 6.0.7
psycopg version: 3.2.12
Postgres version: 18.1
Explain the bug:
Here is my code:
tmp = models.GeneratedField(
db_persist=False, # In here, I've set the column type as virtual
expression=models.Q(standard_symbol_tmp__isnull=False),
null=True,
output_field=models.BooleanField(),
)
And when I do makemigrations all things are good, but on migrating, django says:
SystemCheckError: System check identified some issues:
ERRORS:
symbol.Symbol.tmp: (fields.E221) PostgreSQL does not support non-persisted GeneratedFields.
HINT: Set db_persist=True on the field.
While I know that Postgres supports the VIRTUAL and STORED generated columns, here is the postgres release note ref:
https://www.postgresql.org/about/news/postgresql-18-released-3142/
While the migration file is created and is like:
class Migration(migrations.Migration):
# ...rest of the code ...
operations = [
migrations.AddField(
model_name="symbol",
name="tmp",
field=models.GeneratedField(
db_persist=False,
expression=models.Q(("standard_symbol_tmp__isnull", False)),
null=True,
output_field=models.BooleanField(),
),
),
]
And when I set db_persist to True AND DO NOT TOUCH THE migration file and migrate, all things are good, column creates as VIRTUAL in postgres, NOT STORED.
A quick fix
I played with the migration files, when I changed the
db_persist=Truein mymodels.pyfile, I knew that if I runmakemigrationsone more time, django will create a new migration file for me which changes my VIRTUAL column to STORED, that I didn't wanted, so I did like:db_persist=Truemakemigrationsone more time to have a migration file like:operations = [ migrations.AlterField( model_name="symbol", name="tmp", field=models.GeneratedField( db_persist=True, # 👈 This would change the VIRTUAL to STORED in DB, which is not good expression=models.Q(("standard_symbol_tmp__isnull", False)), null=True, output_field=models.BooleanField(), ), ), ]operations = [ migrations.SeparateDatabaseAndState( state_operations=[ migrations.AlterField( model_name="symbol", name="tmp", field=models.GeneratedField( db_persist=True, expression=models.Q(("standard_symbol_tmp__isnull", False)), null=True, output_field=models.BooleanField(), ), ), ], database_operations=[], # 👈 nothing runs against the DB ), ]Then when I run the
migrate, Django's migration state updated and my DB DIDN'T CHANGED.