Opened 2 years ago

Closed 2 years ago

Last modified 2 years ago

#33914 closed Uncategorized (duplicate)

App level default_auto_field is ignored for m2m through tables

Reported by: Borislav Ivanov Owned by: nobody
Component: Database layer (models, ORM) Version: 3.2
Severity: Normal Keywords: default_auto_field
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When default_auto_field is defined on app level, it is ignored for
m2m through tables. This effectively defaults them to what is defined
in DEFAULT_AUTO_FIELD setting.

This happens in two different code paths, ultimately affecting
Options::_get_default_pk_class:

  1. When AppConfigStub is supplied instead of AppConfig it is stripped from most of the properties including default_auto_field.
  2. When the first migration for a given app is applied, we don't get any app config as it is lazily registered in StateApps::register_models. As this is the first model for this app, the config is no there yet.

Here's modified configuration for polls app that demonstrates the issue:

mysite/settings.py:

...
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'empty',
    }
}
...
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'

mysite/polls/apps.py:

...
class PollsConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'polls'

mysite/polls/models.py:

...
class KlassA(models.Model):
    field_a = models.CharField(max_length=200)


class KlassB(models.Model):
    field_b = models.CharField(max_length=200)
    m2m_to_a = models.ManyToManyField(
        KlassA, blank=True
    )

Then run makemigrations and sqlmigrate polls 0001_initial:

BEGIN;
--
-- Create model KlassA
--
CREATE TABLE "polls_klassa" ("id" bigserial NOT NULL PRIMARY KEY, "field_a" varchar(200) NOT NULL);
--
-- Create model KlassB
--
CREATE TABLE "polls_klassb" ("id" bigserial NOT NULL PRIMARY KEY, "field_b" varchar(200) NOT NULL);
CREATE TABLE "polls_klassb_m2m_to_a" ("id" serial NOT NULL PRIMARY KEY, "klassb_id" bigint NOT NULL, "klassa_id" bigint NOT NULL);
ALTER TABLE "polls_klassb_m2m_to_a" ADD CONSTRAINT "polls_klassb_m2m_to_a_klassb_id_klassa_id_05b47d06_uniq" UNIQUE ("klassb_id", "klassa_id");
ALTER TABLE "polls_klassb_m2m_to_a" ADD CONSTRAINT "polls_klassb_m2m_to_a_klassb_id_58ef37e1_fk_polls_klassb_id" FOREIGN KEY ("klassb_id") REFERENCES "polls_klassb" ("id") DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE "polls_klassb_m2m_to_a" ADD CONSTRAINT "polls_klassb_m2m_to_a_klassa_id_b63f26b4_fk_polls_klassa_id" FOREIGN KEY ("klassa_id") REFERENCES "polls_klassa" ("id") DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "polls_klassb_m2m_to_a_klassb_id_58ef37e1" ON "polls_klassb_m2m_to_a" ("klassb_id");
CREATE INDEX "polls_klassb_m2m_to_a_klassa_id_b63f26b4" ON "polls_klassb_m2m_to_a" ("klassa_id");
COMMIT;

Here we get CREATE TABLE "polls_klassb_m2m_to_a" ("id" serial NOT NULL PRIMARY KEY...

If we change in settings.py DEFAULT_AUTO_FIELD to django.db.models.BigAutoField we get CREATE TABLE "polls_klassb_m2m_to_a" ("id" bigserial NOT NULL PRIMARY KEY...

I did a little bit of research and found out 2 probable causes affecting
Options::_get_default_pk_class:

  1. When AppConfigStub is supplied instead of AppConfig it is stripped

from most of the properties including default_auto_field.

  1. When the first migration for a given app is applied, we don't get

any app config as it is lazily registered in StateApps::register_models.
As this is the first model for this app, the config is no there yet.

Change History (3)

comment:1 by Mariusz Felisiak, 2 years ago

Component: MigrationsDatabase layer (models, ORM)
Resolution: duplicate
Status: newclosed

Duplicate of #32674, see also a note in DEFAULT_AUTO_FIELD docs.

in reply to:  1 ; comment:2 by Borislav Ivanov, 2 years ago

Replying to Mariusz Felisiak:

Duplicate of #32674, see also a note in DEFAULT_AUTO_FIELD docs.

I see your point here, however this is not exactly the same case.

#32674 refers to change in DEFAULT_AUTO_FIELD not being reflected in a migration. This report refers to app level default_auto_field not taking precedence over DEFAULT_AUTO_FIELD as stated in https://docs.djangoproject.com/en/4.1/ref/models/fields/#primary-key.

Having said this I do understand this being postponed as feature request, just wanted to be sure that the use case is clear enough.

in reply to:  2 comment:3 by Mariusz Felisiak, 2 years ago

Replying to Borislav Ivanov:

Replying to Mariusz Felisiak:

Duplicate of #32674, see also a note in DEFAULT_AUTO_FIELD docs.

I see your point here, however this is not exactly the same case.

#32674 refers to change in DEFAULT_AUTO_FIELD not being reflected in a migration. This report refers to app level default_auto_field not taking precedence over DEFAULT_AUTO_FIELD as stated in https://docs.djangoproject.com/en/4.1/ref/models/fields/#primary-key.

Having said this I do understand this being postponed as feature request, just wanted to be sure that the use case is clear enough.

As far as I'm aware fixing #32674 should also fix a precedence.

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