Opened 6 weeks ago
Last modified 6 weeks ago
#36545 closed Bug
On Postgres, removing a generated field and its dependent field generates an invalid migration with makemigrations — at Version 1
Reported by: | john-parton | Owned by: | |
---|---|---|---|
Component: | Migrations | Version: | 5.2 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
When running 'makemigrations' to remove a GeneratedField and a field that it depends, produces a migration that cannot run.
Consider the following example model:
class ProductImage(models.Model): type = models.TextField() is_dupe = models.BooleanField(editable=False, null=True, default=None) visible = models.GeneratedField( expression=( Case( When( Q(type="hidden") | Q(is_dupe=True), then=Value(False), ), default=Value(True), ) ), output_field=models.BooleanField(), db_persist=True, )
Removing the is_dupe
and visible
fields produces the expected migration:
from django.db import migrations class Migration(migrations.Migration): dependencies = [ ("catalog", "0259_alter_productimage_options"), ] operations = [ migrations.RemoveField( model_name="productimage", name="is_dupe", ), migrations.RemoveField( model_name="productimage", name="visible", ), ]
Running the migration produces this error
File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/backends/utils.py", line 103, in _execute return self.cursor.execute(sql) ~~~~~~~~~~~~~~~~~~~^^^^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/psycopg/cursor.py", line 97, in execute raise ex.with_traceback(None) psycopg.errors.UndefinedColumn: column "visible" of relation "catalog_productimage" does not exist The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/home/john/Code/ecom/code/src/./manage.py", line 30, in <module> execute_from_command_line(sys.argv) ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line utility.execute() ~~~~~~~~~~~~~~~^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/core/management/__init__.py", line 436, in execute self.fetch_command(subcommand).run_from_argv(self.argv) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/core/management/base.py", line 416, in run_from_argv self.execute(*args, **cmd_options) ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/core/management/base.py", line 460, in execute output = self.handle(*args, **options) File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/core/management/base.py", line 107, in wrapper res = handle_func(*args, **kwargs) File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/core/management/commands/migrate.py", line 353, in handle post_migrate_state = executor.migrate( targets, ...<3 lines>... fake_initial=fake_initial, ) File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/migrations/executor.py", line 135, in migrate state = self._migrate_all_forwards( state, plan, full_plan, fake=fake, fake_initial=fake_initial ) File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/migrations/executor.py", line 167, in _migrate_all_forwards state = self.apply_migration( state, migration, fake=fake, fake_initial=fake_initial ) File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/migrations/executor.py", line 255, in apply_migration state = migration.apply(state, schema_editor) File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/migrations/migration.py", line 132, in apply operation.database_forwards( ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ self.app_label, schema_editor, old_state, project_state ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/migrations/operations/fields.py", line 174, in database_forwards schema_editor.remove_field( ~~~~~~~~~~~~~~~~~~~~~~~~~~^ from_model, from_model._meta.get_field(self.name) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/backends/base/schema.py", line 829, in remove_field self.execute(sql) ~~~~~~~~~~~~^^^^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/pgtrigger/migrations.py", line 483, in execute return super().execute(*args, **kwargs) ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/backends/postgresql/schema.py", line 48, in execute return super().execute(sql, None) ~~~~~~~~~~~~~~~^^^^^^^^^^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/backends/base/schema.py", line 204, in execute cursor.execute(sql, params) ~~~~~~~~~~~~~~^^^^^^^^^^^^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/backends/utils.py", line 122, in execute return super().execute(sql, params) ~~~~~~~~~~~~~~~^^^^^^^^^^^^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/backends/utils.py", line 79, in execute return self._execute_with_wrappers( ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ sql, params, many=False, executor=self._execute ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers return executor(sql, params, many, context) File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/backends/utils.py", line 100, in _execute with self.db.wrap_database_errors: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/utils.py", line 91, in __exit__ raise dj_exc_value.with_traceback(traceback) from exc_value File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/django/db/backends/utils.py", line 103, in _execute return self.cursor.execute(sql) ~~~~~~~~~~~~~~~~~~~^^^^^ File "/home/john/Code/ecom/.venv/lib/python3.13/site-packages/psycopg/cursor.py", line 97, in execute raise ex.with_traceback(None) django.db.utils.ProgrammingError: column "visible" of relation "catalog_productimage" does not exist
Manually reordering the migration so that generated field is deleted before the dependent field:
class Migration(migrations.Migration): dependencies = [ ("catalog", "0259_alter_productimage_options"), ] operations = [ migrations.RemoveField( model_name="productimage", name="visible", ), migrations.RemoveField( model_name="productimage", name="is_dupe", ), ]
And now the migration runs as expected.
There might be some other subtle errors around GeneratedField and migrations, but this is the most obvious one I could reproduce.
Could not find a duplicate: https://code.djangoproject.com/query?description=~generated+field+migration&status=assigned&status=closed&status=new&order=id&desc=1&col=id&col=summary&col=owner&col=type&col=component