diff --git a/django/db/models/options.py b/django/db/models/options.py index c6ddd2a6f9..74a362e99c 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -255,6 +255,11 @@ class Options(object): field = already_created[0] field.primary_key = True self.setup_pk(field) + if not field.remote_field.parent_link: + warnings.warn( + 'Add parent_link=True to %s as an implicit link is ' + 'deprecated.' % field, RemovedInDjango20Warning + ) else: auto = AutoField(verbose_name='ID', primary_key=True, auto_created=True) model.add_to_class('id', auto) diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 9b2304137d..97534185b2 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -160,6 +160,9 @@ details on these changes. * The ``django.contrib.gis.utils.precision_wkt()`` function will be removed. +* In multi-table inheritance, implicit promotion of a ``OneToOneField`` to a + ``parent_link`` will be removed. + .. _deprecation-removed-in-1.10: 1.10 diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt index e63b3bf42b..137fe9720e 100644 --- a/docs/releases/1.10.txt +++ b/docs/releases/1.10.txt @@ -980,6 +980,9 @@ Miscellaneous favor of class-based views :class:`~django.views.i18n.JavaScriptCatalog` and :class:`~django.views.i18n.JSONCatalog`. +* In multi-table inheritance, implicit promotion of a ``OneToOneField`` to a + ``parent_link`` is deprecated. Add ``parent_link=True`` to such fields. + .. _removed-features-1.10: Features removed in 1.10 diff --git a/tests/invalid_models_tests/test_models.py b/tests/invalid_models_tests/test_models.py index e4b3105574..b8f15cae60 100644 --- a/tests/invalid_models_tests/test_models.py +++ b/tests/invalid_models_tests/test_models.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import unittest +import warnings from django.conf import settings from django.core.checks import Error @@ -739,3 +740,24 @@ class OtherModelTests(SimpleTestCase): ) ] self.assertEqual(errors, expected) + + def test_missing_parent_link(self): + with warnings.catch_warnings(record=True) as warns: + warnings.simplefilter('always') + + class Place(models.Model): + pass + + class ParkingLot(Place): + # In lieu of any other connector, an existing OneToOneField will be + # promoted to the primary key. + parent = models.OneToOneField(Place, models.CASCADE) + + self.assertEqual(len(warns), 1) + msg = str(warns[0].message) + self.assertEqual( + msg, + 'Add parent_link=True to invalid_models_tests.ParkingLot.parent ' + 'as an implicit link is deprecated.' + ) + self.assertEqual(ParkingLot._meta.pk.name, 'parent') diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py index 1c6711bc8a..daeb5d500e 100644 --- a/tests/migrations/test_operations.py +++ b/tests/migrations/test_operations.py @@ -123,6 +123,7 @@ class OperationTestBase(MigrationTestBase): 'Pony', models.CASCADE, auto_created=True, + parent_link=True, primary_key=True, to_field='id', serialize=False, diff --git a/tests/model_inheritance_regress/models.py b/tests/model_inheritance_regress/models.py index ad905db981..b5bc75061d 100644 --- a/tests/model_inheritance_regress/models.py +++ b/tests/model_inheritance_regress/models.py @@ -45,12 +45,6 @@ class ParkingLot(Place): return "%s the parking lot" % self.name -class ParkingLot2(Place): - # In lieu of any other connector, an existing OneToOneField will be - # promoted to the primary key. - parent = models.OneToOneField(Place, models.CASCADE) - - class ParkingLot3(Place): # The parent_link connector need not be the pk on the model. primary_key = models.AutoField(primary_key=True) diff --git a/tests/model_inheritance_regress/tests.py b/tests/model_inheritance_regress/tests.py index f7044144ec..7499e4e42f 100644 --- a/tests/model_inheritance_regress/tests.py +++ b/tests/model_inheritance_regress/tests.py @@ -13,10 +13,9 @@ from django.test import TestCase from .models import ( ArticleWithAuthor, BachelorParty, BirthdayParty, BusStation, Child, DerivedM, InternalCertificationAudit, ItalianRestaurant, M2MChild, - MessyBachelorParty, ParkingLot, ParkingLot2, ParkingLot3, ParkingLot4A, - ParkingLot4B, Person, Place, Profile, QualityControl, Restaurant, - SelfRefChild, SelfRefParent, Senator, Supplier, TrainStation, User, - Wholesaler, + MessyBachelorParty, ParkingLot, ParkingLot3, ParkingLot4A, ParkingLot4B, + Person, Place, Profile, QualityControl, Restaurant, SelfRefChild, + SelfRefParent, Senator, Supplier, TrainStation, User, Wholesaler, ) @@ -293,20 +292,11 @@ class ModelInheritanceTest(TestCase): def test_use_explicit_o2o_to_parent_as_pk(self): """ - Regression tests for #10406 - If there's a one-to-one link between a child model and the parent and - no explicit pk declared, we can use the one-to-one link as the pk on - the child. + The connector from child to parent need not be the pk on the child. """ - self.assertEqual(ParkingLot2._meta.pk.name, "parent") - - # However, the connector from child to parent need not be the pk on - # the child at all. self.assertEqual(ParkingLot3._meta.pk.name, "primary_key") # the child->parent link - self.assertEqual( - ParkingLot3._meta.get_ancestor_link(Place).name, - "parent") + self.assertEqual(ParkingLot3._meta.get_ancestor_link(Place).name, "parent") def test_use_explicit_o2o_to_parent_from_abstract_model(self): self.assertEqual(ParkingLot4A._meta.pk.name, "parent") diff --git a/tests/serializers/models/data.py b/tests/serializers/models/data.py index 98d59622d7..c95fa77ad9 100644 --- a/tests/serializers/models/data.py +++ b/tests/serializers/models/data.py @@ -301,7 +301,7 @@ class InheritBaseModel(BaseModel): class ExplicitInheritBaseModel(BaseModel): - parent = models.OneToOneField(BaseModel, models.CASCADE) + parent = models.OneToOneField(BaseModel, models.CASCADE, parent_link=True) child_data = models.IntegerField()