From 026574e03c6b6fd20a45f97b0470afb70e41fda4 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Mon, 28 Mar 2016 14:14:24 -0400 Subject: [PATCH] [1.9.x] Fixed #26413 -- Fixed a regression with abstract model inheritance and explicit parent links. Thanks Trac alias trkjgrdg for the report and Tim for investigation and review. Backport of 67cf5efa31acb2916034afb15610b700695dfcb0 from master --- django/db/models/base.py | 10 +++++++++- docs/releases/1.9.5.txt | 3 +++ tests/model_inheritance/tests.py | 23 ++++++++++++++++++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/django/db/models/base.py b/django/db/models/base.py index e1a94d34d1..5635fabd6a 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -245,13 +245,21 @@ class ModelBase(type): field = None new_class._meta.parents[base] = field else: + base_parents = base._meta.parents.copy() + # .. and abstract ones. for field in parent_fields: new_field = copy.deepcopy(field) new_class.add_to_class(field.name, new_field) + # Replace parent links defined on this base by the new + # field as it will be appropriately resolved if required. + if field.one_to_one: + for parent, parent_link in base_parents.items(): + if field == parent_link: + base_parents[parent] = new_field # Pass any non-abstract parent classes onto child. - new_class._meta.parents.update(base._meta.parents) + new_class._meta.parents.update(base_parents) # Inherit managers from the abstract base classes. new_class.copy_managers(base._meta.abstract_managers) diff --git a/docs/releases/1.9.5.txt b/docs/releases/1.9.5.txt index 6f073c5c07..7c50e4883d 100644 --- a/docs/releases/1.9.5.txt +++ b/docs/releases/1.9.5.txt @@ -40,3 +40,6 @@ Bugfixes * Restored the functionality of the admin's ``raw_id_fields`` in ``list_editable`` (:ticket:`26387`). + +* Fixed a regression with abstract model inheritance and explicit parent links + (:ticket:`26413`). diff --git a/tests/model_inheritance/tests.py b/tests/model_inheritance/tests.py index 1869864a9a..fad47a69ec 100644 --- a/tests/model_inheritance/tests.py +++ b/tests/model_inheritance/tests.py @@ -2,9 +2,10 @@ from __future__ import unicode_literals from operator import attrgetter +from django.apps.registry import Apps from django.core.exceptions import FieldError, ValidationError from django.core.management import call_command -from django.db import connection +from django.db import connection, models from django.test import TestCase, TransactionTestCase from django.test.utils import CaptureQueriesContext from django.utils import six @@ -130,6 +131,26 @@ class ModelInheritanceTests(TestCase): m = MixinModel() self.assertEqual(m.other_attr, 1) + def test_abstract_parent_link(self): + test_apps = Apps(['model_inheritance']) + + class A(models.Model): + class Meta: + apps = test_apps + + class B(A): + a = models.OneToOneField('A', parent_link=True, on_delete=models.CASCADE) + + class Meta: + apps = test_apps + abstract = True + + class C(B): + class Meta: + apps = test_apps + + self.assertIs(C._meta.parents[A], C._meta.get_field('a')) + class ModelInheritanceDataTests(TestCase): @classmethod