#34928 closed Bug (duplicate)

makemigrations when adding a ForeignKey to a model with a UniqueConstraint must create the field before creating the constraint

Reported by: yonatanramirez Owned by: nobody
Component: Migrations Version: 4.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

This issue looks like #25551 but with UniqueConstraint and not unique_together.

from django.db import models
 
+class Author(models.Model):
+    name = models.CharField(max_length=255)
+
 class Book(models.Model):
     name = models.CharField(max_length=255)
+    author = models.ForeignKey(Author, on_delete=models.CASCADE, null=True)
+
+    class Meta:
+        constraints = [
+            models.UniqueConstraint(
+                fields=['name', 'author'],
+                name='unique_book_name_author'
+            )
+        ]

This is the output of the makemigration command

Migrations for 'issue':
  issue/migrations/0002_author_book_unique_book_name_author_book_author.py
    - Create model Author
    - Create constraint unique_book_name_author on model book
    - Add field author to book

And the portion of the migration file:

operations = [
        migrations.CreateModel(
            name='Author',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=255)),
            ],
        ),
        migrations.AddConstraint(
            model_name='book',
            constraint=models.UniqueConstraint(fields=('name', 'author'), name='unique_book_name_author'),
        ),
        migrations.AddField(
            model_name='book',
            name='author',
            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='issue.author'),
        ),
    ]

The stacktrace:

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, issue, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying issue.0001_initial... OK
  Applying issue.0002_author_book_unique_book_name_author_book_author...Traceback (most recent call last):
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/models/options.py", line 681, in get_field
    return self.fields_map[field_name]
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^
KeyError: 'author'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/yramirez/playground/django/essai/manage.py", line 22, in <module>
    main()
  File "/home/yramirez/playground/django/essai/manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/core/management/__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/core/management/base.py", line 412, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/core/management/base.py", line 458, in execute
    output = self.handle(*args, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/core/management/base.py", line 106, in wrapper
    res = handle_func(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/core/management/commands/migrate.py", line 356, in handle
    post_migrate_state = executor.migrate(
                         ^^^^^^^^^^^^^^^^^
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/migrations/executor.py", line 135, in migrate
    state = self._migrate_all_forwards(
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/migrations/executor.py", line 167, in _migrate_all_forwards
    state = self.apply_migration(
            ^^^^^^^^^^^^^^^^^^^^^
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/migrations/executor.py", line 252, in apply_migration
    state = migration.apply(state, schema_editor)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/migrations/migration.py", line 132, in apply
    operation.database_forwards(
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/migrations/operations/models.py", line 1135, in database_forwards
    schema_editor.add_constraint(model, self.constraint)
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/backends/sqlite3/schema.py", line 562, in add_constraint
    self._remake_table(model)
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/backends/sqlite3/schema.py", line 331, in _remake_table
    self.create_model(new_model)
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/backends/base/schema.py", line 448, in create_model
    sql, params = self.table_sql(model)
                  ^^^^^^^^^^^^^^^^^^^^^
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/backends/base/schema.py", line 267, in table_sql
    constraints = [
                  ^
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/backends/base/schema.py", line 268, in <listcomp>
    constraint.constraint_sql(model, self)
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/models/constraints.py", line 216, in constraint_sql
    fields = [model._meta.get_field(field_name) for field_name in self.fields]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/models/constraints.py", line 216, in <listcomp>
    fields = [model._meta.get_field(field_name) for field_name in self.fields]
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/yramirez/.pyenv/versions/django/lib/python3.11/site-packages/django/db/models/options.py", line 683, in get_field
    raise FieldDoesNotExist(
django.core.exceptions.FieldDoesNotExist: NewBook has no field named 'author'

Change History (1)

comment:1 by Mariusz Felisiak, 11 months ago

Resolution: duplicate
Status: newclosed

Duplicate of #34333, fixed in 4b1bfea2846f66f504265cec46ee1fe94ee9c98b (Django 5.0+).

Note: See TracTickets for help on using tickets.
Back to Top