Loading django/db/models/fields/related.py +15 −6 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ from .reverse_related import ( RECURSIVE_RELATIONSHIP_CONSTANT = 'self' def resolve_relation(scope_model, relation): def resolve_relation(scope_model, relation, resolve_recursive_relationship=True): """ Transform relation into a model or fully-qualified model string of the form "app_label.ModelName", relative to scope_model. Loading @@ -54,11 +54,10 @@ def resolve_relation(scope_model, relation): """ # Check for recursive relations if relation == RECURSIVE_RELATIONSHIP_CONSTANT: if resolve_recursive_relationship: relation = scope_model # Look for an "app.Model" relation if isinstance(relation, six.string_types): if "." not in relation: elif isinstance(relation, six.string_types) and '.' not in relation: relation = "%s.%s" % (scope_model._meta.app_label, relation) return relation Loading Loading @@ -306,6 +305,11 @@ class RelatedField(Field): field.remote_field.model = related field.do_related_class(related, model) lazy_related_operation(resolve_related_class, cls, self.remote_field.model, field=self) else: # Bind a lazy reference to the app in which the model is defined. self.remote_field.model = resolve_relation( cls, self.remote_field.model, resolve_recursive_relationship=False ) def get_forward_related_filter(self, obj): """ Loading Loading @@ -1577,6 +1581,11 @@ class ManyToManyField(RelatedField): lazy_related_operation(resolve_through_model, cls, self.remote_field.through, field=self) elif not cls._meta.swapped: self.remote_field.through = create_many_to_many_intermediary_model(self, cls) else: # Bind a lazy reference to the app in which the model is defined. self.remote_field.through = resolve_relation( cls, self.remote_field.through, resolve_recursive_relationship=False ) # Add the descriptor for the m2m relation. setattr(cls, self.name, ManyToManyDescriptor(self.remote_field, reverse=False)) Loading docs/releases/1.9.2.txt +5 −0 Original line number Diff line number Diff line Loading @@ -30,3 +30,8 @@ Bugfixes ``db_index=True`` or ``unique=True`` to a ``CharField`` or ``TextField`` that already had the other specified, or when removing one of them from a field that had both (:ticket:`26034`). * Fixed a regression where defining a relation on an abstract model's field using a string model name without an app_label no longer resolved that reference to the abstract model's app if using that model in another application (:ticket`25858`). No newline at end of file tests/model_fields/tests.py +54 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from decimal import Decimal from django import forms, test from django.apps import apps from django.apps.registry import Apps from django.core import checks, validators from django.core.exceptions import ValidationError from django.db import IntegrityError, connection, models, transaction Loading Loading @@ -247,6 +248,28 @@ class ForeignKeyTests(test.TestCase): "Pending lookup added for a foreign key on an abstract model" ) def test_abstract_model_app_relative_foreign_key(self): test_apps = Apps(['model_fields', 'model_fields.tests']) class Refered(models.Model): class Meta: apps = test_apps app_label = 'model_fields' class AbstractReferent(models.Model): reference = models.ForeignKey('Refered', on_delete=models.CASCADE) class Meta: app_label = 'model_fields' abstract = True class ConcreteReferent(AbstractReferent): class Meta: apps = test_apps app_label = 'tests' self.assertEqual(ConcreteReferent._meta.get_field('reference').related_model, Refered) class ManyToManyFieldTests(test.SimpleTestCase): def test_abstract_model_pending_operations(self): Loading @@ -269,6 +292,37 @@ class ManyToManyFieldTests(test.SimpleTestCase): "Pending lookup added for a many-to-many field on an abstract model" ) def test_abstract_model_app_relative_foreign_key(self): test_apps = Apps(['model_fields', 'model_fields.tests']) class Refered(models.Model): class Meta: apps = test_apps app_label = 'model_fields' class Through(models.Model): refered = models.ForeignKey('Refered', on_delete=models.CASCADE) referent = models.ForeignKey('tests.ConcreteReferent', on_delete=models.CASCADE) class Meta: apps = test_apps app_label = 'model_fields' class AbstractReferent(models.Model): reference = models.ManyToManyField('Refered', through='Through') class Meta: app_label = 'model_fields' abstract = True class ConcreteReferent(AbstractReferent): class Meta: apps = test_apps app_label = 'tests' self.assertEqual(ConcreteReferent._meta.get_field('reference').related_model, Refered) self.assertEqual(ConcreteReferent.reference.through, Through) class TextFieldTests(test.TestCase): def test_to_python(self): Loading Loading
django/db/models/fields/related.py +15 −6 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ from .reverse_related import ( RECURSIVE_RELATIONSHIP_CONSTANT = 'self' def resolve_relation(scope_model, relation): def resolve_relation(scope_model, relation, resolve_recursive_relationship=True): """ Transform relation into a model or fully-qualified model string of the form "app_label.ModelName", relative to scope_model. Loading @@ -54,11 +54,10 @@ def resolve_relation(scope_model, relation): """ # Check for recursive relations if relation == RECURSIVE_RELATIONSHIP_CONSTANT: if resolve_recursive_relationship: relation = scope_model # Look for an "app.Model" relation if isinstance(relation, six.string_types): if "." not in relation: elif isinstance(relation, six.string_types) and '.' not in relation: relation = "%s.%s" % (scope_model._meta.app_label, relation) return relation Loading Loading @@ -306,6 +305,11 @@ class RelatedField(Field): field.remote_field.model = related field.do_related_class(related, model) lazy_related_operation(resolve_related_class, cls, self.remote_field.model, field=self) else: # Bind a lazy reference to the app in which the model is defined. self.remote_field.model = resolve_relation( cls, self.remote_field.model, resolve_recursive_relationship=False ) def get_forward_related_filter(self, obj): """ Loading Loading @@ -1577,6 +1581,11 @@ class ManyToManyField(RelatedField): lazy_related_operation(resolve_through_model, cls, self.remote_field.through, field=self) elif not cls._meta.swapped: self.remote_field.through = create_many_to_many_intermediary_model(self, cls) else: # Bind a lazy reference to the app in which the model is defined. self.remote_field.through = resolve_relation( cls, self.remote_field.through, resolve_recursive_relationship=False ) # Add the descriptor for the m2m relation. setattr(cls, self.name, ManyToManyDescriptor(self.remote_field, reverse=False)) Loading
docs/releases/1.9.2.txt +5 −0 Original line number Diff line number Diff line Loading @@ -30,3 +30,8 @@ Bugfixes ``db_index=True`` or ``unique=True`` to a ``CharField`` or ``TextField`` that already had the other specified, or when removing one of them from a field that had both (:ticket:`26034`). * Fixed a regression where defining a relation on an abstract model's field using a string model name without an app_label no longer resolved that reference to the abstract model's app if using that model in another application (:ticket`25858`). No newline at end of file
tests/model_fields/tests.py +54 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from decimal import Decimal from django import forms, test from django.apps import apps from django.apps.registry import Apps from django.core import checks, validators from django.core.exceptions import ValidationError from django.db import IntegrityError, connection, models, transaction Loading Loading @@ -247,6 +248,28 @@ class ForeignKeyTests(test.TestCase): "Pending lookup added for a foreign key on an abstract model" ) def test_abstract_model_app_relative_foreign_key(self): test_apps = Apps(['model_fields', 'model_fields.tests']) class Refered(models.Model): class Meta: apps = test_apps app_label = 'model_fields' class AbstractReferent(models.Model): reference = models.ForeignKey('Refered', on_delete=models.CASCADE) class Meta: app_label = 'model_fields' abstract = True class ConcreteReferent(AbstractReferent): class Meta: apps = test_apps app_label = 'tests' self.assertEqual(ConcreteReferent._meta.get_field('reference').related_model, Refered) class ManyToManyFieldTests(test.SimpleTestCase): def test_abstract_model_pending_operations(self): Loading @@ -269,6 +292,37 @@ class ManyToManyFieldTests(test.SimpleTestCase): "Pending lookup added for a many-to-many field on an abstract model" ) def test_abstract_model_app_relative_foreign_key(self): test_apps = Apps(['model_fields', 'model_fields.tests']) class Refered(models.Model): class Meta: apps = test_apps app_label = 'model_fields' class Through(models.Model): refered = models.ForeignKey('Refered', on_delete=models.CASCADE) referent = models.ForeignKey('tests.ConcreteReferent', on_delete=models.CASCADE) class Meta: apps = test_apps app_label = 'model_fields' class AbstractReferent(models.Model): reference = models.ManyToManyField('Refered', through='Through') class Meta: app_label = 'model_fields' abstract = True class ConcreteReferent(AbstractReferent): class Meta: apps = test_apps app_label = 'tests' self.assertEqual(ConcreteReferent._meta.get_field('reference').related_model, Refered) self.assertEqual(ConcreteReferent.reference.through, Through) class TextFieldTests(test.TestCase): def test_to_python(self): Loading