﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
32484	Can't access inherited fields from multi-table inherited model when using apps from MigrationExecutor	Max N	nobody	"I came across an issue when using the `apps` value from the `MigrationExecutor`. If I use this `apps.get_model` I can't use fields from a multi-table inherited model.

I have two applications (`api` and `labels`), with two models (`DocumentLabel` and `Label` respectively). `DocumentLabel` uses multi-table inheritance from `Label`. If I use the `MigrationExecutor` to load a migration, and then use `apps.get_model` from that state (`executor.loader.project_state(migrate_from).apps`) then the returned model from `get_model` of `DocumentLabel` behaves incorrectly, it doesn't allow me to reference the fields from the inherited `Label` model. It also throws errors if I try to access the `label_ptr` field.

If I use `apps` from `django.apps` it works as expected.

For example, `api.models` contains:

{{{#!python
class DocumentLabel(LabelsLabel):
    """"""Label for organising documents.""""""

    assigned_to = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL
    )
    workspace = models.ForeignKey(""Workspace"", on_delete=models.SET_NULL, null=True)

    class Meta:
        constraints: List[BaseConstraint] = []
}}}

The `DocumentLabel` inherits from the `Label` class from another app `labels.models`:

{{{#!python
class Label(CreatedAtUpdatedAt):  # type: ignore
    """"""The label model should be used as default""""""

    name = models.TextField()
    type = models.ForeignKey(
        f""{LABEL_TYPE_MODEL_APP}.{LABEL_TYPE_MODEL_NAME}"", on_delete=models.CASCADE,
    )

    class Meta:
        constraints = [
            UniqueConstraint(
                fields=[""name"", ""type""],
                name=""%(app_label)s_label_unique_name_and_type"",
            )
        ]
}}}

I am testing a migration, so I am using the MigrationExecutor to go to a certain migration, it does not change the models in question. When I try to access the `type` field of the `Label` model through the `DocumentLabel` model, something that is possible usually, I get an exception saying that `type` is not set on the `DocumentLabel` model. The code:


{{{#!python
executor = MigrationExecutor(connection)
old_apps = executor.loader.project_state(migrate_from).apps
executor.migrate(migrate_from)

LabelType = old_apps.get_model(""api"", ""LabelType"")
DocumentLabel = old_apps.get_model(""api"", ""DocumentLabel"")
project = LabelType.objects.create(name=""Project"")
label = DocumentLabel.objects.create(type=project, name=""test"",workspace=workspace)
}}}

It throws the following:

{{{
Traceback (most recent call last):
  File ""/opt/project/api/tests/test_migrations.py"", line 131, in test_projects_data_migration
    label_1 = DocumentLabel.objects.create(type=project, name=""test"",workspace=workspace)
  File ""/usr/local/lib/python3.8/site-packages/django/db/models/manager.py"", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File ""/usr/local/lib/python3.8/site-packages/django/db/models/query.py"", line 445, in create
    obj = self.model(**kwargs)
  File ""/usr/local/lib/python3.8/site-packages/django/db/models/base.py"", line 501, in __init__
    raise TypeError(""%s() got an unexpected keyword argument '%s'"" % (cls.__name__, kwarg))
TypeError: DocumentLabel() got an unexpected keyword argument 'type'
}}}

Interestingly, `LabelType` is also a model that is using multi-table inheritance from the same application, but that works fine. The only difference I can think of is that `Label` has a `ForeignKey` field in it, but the inherited `LabelType` field has no foreign key.

I also tried to directly set the `label_ptr`:


{{{#!python
LabelType = old_apps.get_model(""api"", ""LabelType"")
Label = old_apps.get_model(""label"", ""Label"")
DocumentLabel = old_apps.get_model(""api"", ""DocumentLabel"")

project = LabelType.objects.create(project=True, name=""Project"", workspace=workspace, allow_multiple=True)
label_label_1 = Label.objects.create(name=""test"", type=project)
label_1 = DocumentLabel.objects.create(label_ptr=label_label_1, workspace=workspace)

for label in DocumentLabel.objects.all():
    print(label.label_ptr)
}}}

It throws the exception:

{{{
Traceback (most recent call last):
  File ""/usr/local/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py"", line 173, in __get__
    rel_obj = self.field.get_cached_value(instance)
  File ""/usr/local/lib/python3.8/site-packages/django/db/models/fields/mixins.py"", line 15, in get_cached_value
    return instance._state.fields_cache[cache_name]
KeyError: 'label_ptr'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File ""/opt/project/api/tests/test_migrations.py"", line 136, in test_projects_data_migration
    print(label.label_ptr)
  File ""/usr/local/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py"", line 187, in __get__
    rel_obj = self.get_object(instance)
  File ""/usr/local/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py"", line 302, in get_object
    kwargs = {field: getattr(instance, field) for field in fields}
  File ""/usr/local/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py"", line 302, in <dictcomp>
    kwargs = {field: getattr(instance, field) for field in fields}
AttributeError: 'DocumentLabel' object has no attribute 'id'
}}}

I looked into the model at that point, and the `label_ptr` is not found. I also looked into the code of `ForwardManyToOneDescriptor` and found that `get_cached_value` throws a `KeyError` exception, which triggers some logic. I tried to 'pre-cache' the related model by doing the following:

{{{#!python
DocumentLabel.objects.all().prefetch_related(""label_ptr"")
}}}

This actually causes the `label_ptr` to be set, but it doesn't allow the 'transparent' ability to query `Label` fields as if they are part of the `DocumentLabel` model."	Bug	closed	Database layer (models, ORM)	3.1	Normal	needsinfo			Unreviewed	0	0	0	0	0	0
