#36545: On Postgres, removing a generated field and its dependent field generates an invalid migration with makemigrations -----------------------------+-------------------------------------- Reporter: john-parton | Type: Bug Status: new | Component: Migrations Version: 5.2 | Severity: Normal Keywords: | Triage Stage: Unreviewed Has patch: 0 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 -----------------------------+-------------------------------------- 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. -- Ticket URL: <https://code.djangoproject.com/ticket/36545> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/django-updates/010701988a929421-66ba10f3-9b4d-4197-9e16-60d92bfd0bec-000000%40eu-central-1.amazonses.com.