Loading django/db/models/fields/related.py +1 −1 Original line number Diff line number Diff line Loading @@ -684,7 +684,7 @@ class ForeignObject(RelatedField): # Internal FK's - i.e., those with a related name ending with '+' - # and swapped models don't get a related descriptor. if not self.remote_field.is_hidden() and not related.related_model._meta.swapped: setattr(cls, related.get_accessor_name(), self.related_accessor_class(related)) setattr(cls._meta.concrete_model, related.get_accessor_name(), self.related_accessor_class(related)) # While 'limit_choices_to' might be a callable, simply pass # it along for later - this is too early because it's still # model load time. Loading django/db/models/fields/related_descriptors.py +1 −1 Original line number Diff line number Diff line Loading @@ -198,7 +198,7 @@ class ForwardManyToOneDescriptor(object): 'Cannot assign None: "%s.%s" does not allow null values.' % (instance._meta.object_name, self.field.name) ) elif value is not None and not isinstance(value, self.field.remote_field.model): elif value is not None and not isinstance(value, self.field.remote_field.model._meta.concrete_model): raise ValueError( 'Cannot assign "%r": "%s.%s" must be a "%s" instance.' % ( value, Loading django/db/models/options.py +10 −3 Original line number Diff line number Diff line Loading @@ -552,15 +552,20 @@ class Options(object): is set as a property on every model. """ related_objects_graph = defaultdict(list) # Map of concrete models to all options of models it represents. # Including its options and all its proxy model ones. concrete_model_classes = defaultdict(list) all_models = self.apps.get_models(include_auto_created=True) for model in all_models: opts = model._meta concrete_model_classes[opts.concrete_model].append(opts) # Abstract model's fields are copied to child models, hence we will # see the fields from the child models. if model._meta.abstract: if opts.abstract: continue fields_with_relations = ( f for f in model._meta._get_fields(reverse=False, include_parents=False) f for f in opts._get_fields(reverse=False, include_parents=False) if f.is_relation and f.related_model is not None ) for f in fields_with_relations: Loading @@ -573,7 +578,9 @@ class Options(object): # __dict__ takes precedence over a data descriptor (such as # @cached_property). This means that the _meta._relation_tree is # only called if related_objects is not in __dict__. related_objects = related_objects_graph[model._meta] related_objects = list(chain.from_iterable( related_objects_graph[opts] for opts in concrete_model_classes[model] )) model._meta.__dict__['_relation_tree'] = related_objects # It seems it is possible that self is not in all_models, so guard # against that with default for get(). Loading docs/releases/1.10.txt +5 −1 Original line number Diff line number Diff line Loading @@ -163,7 +163,11 @@ Migrations Models ^^^^^^ * ... * Reverse foreign keys from proxy models are now propagated to their concrete class. The reverse relation attached by a :class:`~django.db.models.ForeignKey` pointing to a proxy model is now accessible as a descriptor on the proxied model class and may be referenced in queryset filtering. Requests and Responses ^^^^^^^^^^^^^^^^^^^^^^ Loading tests/model_meta/models.py +1 −1 Original line number Diff line number Diff line Loading @@ -113,7 +113,7 @@ class Relating(models.Model): # ForeignKey to ProxyPerson proxyperson = models.ForeignKey(ProxyPerson, models.CASCADE, related_name='relating_proxyperson') proxyperson_hidden = models.ForeignKey(ProxyPerson, models.CASCADE, related_name='+') proxyperson_hidden = models.ForeignKey(ProxyPerson, models.CASCADE, related_name='relating_proxyperson_hidden+') # ManyToManyField to BasePerson basepeople = models.ManyToManyField(BasePerson, related_name='relating_basepeople') Loading Loading
django/db/models/fields/related.py +1 −1 Original line number Diff line number Diff line Loading @@ -684,7 +684,7 @@ class ForeignObject(RelatedField): # Internal FK's - i.e., those with a related name ending with '+' - # and swapped models don't get a related descriptor. if not self.remote_field.is_hidden() and not related.related_model._meta.swapped: setattr(cls, related.get_accessor_name(), self.related_accessor_class(related)) setattr(cls._meta.concrete_model, related.get_accessor_name(), self.related_accessor_class(related)) # While 'limit_choices_to' might be a callable, simply pass # it along for later - this is too early because it's still # model load time. Loading
django/db/models/fields/related_descriptors.py +1 −1 Original line number Diff line number Diff line Loading @@ -198,7 +198,7 @@ class ForwardManyToOneDescriptor(object): 'Cannot assign None: "%s.%s" does not allow null values.' % (instance._meta.object_name, self.field.name) ) elif value is not None and not isinstance(value, self.field.remote_field.model): elif value is not None and not isinstance(value, self.field.remote_field.model._meta.concrete_model): raise ValueError( 'Cannot assign "%r": "%s.%s" must be a "%s" instance.' % ( value, Loading
django/db/models/options.py +10 −3 Original line number Diff line number Diff line Loading @@ -552,15 +552,20 @@ class Options(object): is set as a property on every model. """ related_objects_graph = defaultdict(list) # Map of concrete models to all options of models it represents. # Including its options and all its proxy model ones. concrete_model_classes = defaultdict(list) all_models = self.apps.get_models(include_auto_created=True) for model in all_models: opts = model._meta concrete_model_classes[opts.concrete_model].append(opts) # Abstract model's fields are copied to child models, hence we will # see the fields from the child models. if model._meta.abstract: if opts.abstract: continue fields_with_relations = ( f for f in model._meta._get_fields(reverse=False, include_parents=False) f for f in opts._get_fields(reverse=False, include_parents=False) if f.is_relation and f.related_model is not None ) for f in fields_with_relations: Loading @@ -573,7 +578,9 @@ class Options(object): # __dict__ takes precedence over a data descriptor (such as # @cached_property). This means that the _meta._relation_tree is # only called if related_objects is not in __dict__. related_objects = related_objects_graph[model._meta] related_objects = list(chain.from_iterable( related_objects_graph[opts] for opts in concrete_model_classes[model] )) model._meta.__dict__['_relation_tree'] = related_objects # It seems it is possible that self is not in all_models, so guard # against that with default for get(). Loading
docs/releases/1.10.txt +5 −1 Original line number Diff line number Diff line Loading @@ -163,7 +163,11 @@ Migrations Models ^^^^^^ * ... * Reverse foreign keys from proxy models are now propagated to their concrete class. The reverse relation attached by a :class:`~django.db.models.ForeignKey` pointing to a proxy model is now accessible as a descriptor on the proxied model class and may be referenced in queryset filtering. Requests and Responses ^^^^^^^^^^^^^^^^^^^^^^ Loading
tests/model_meta/models.py +1 −1 Original line number Diff line number Diff line Loading @@ -113,7 +113,7 @@ class Relating(models.Model): # ForeignKey to ProxyPerson proxyperson = models.ForeignKey(ProxyPerson, models.CASCADE, related_name='relating_proxyperson') proxyperson_hidden = models.ForeignKey(ProxyPerson, models.CASCADE, related_name='+') proxyperson_hidden = models.ForeignKey(ProxyPerson, models.CASCADE, related_name='relating_proxyperson_hidden+') # ManyToManyField to BasePerson basepeople = models.ManyToManyField(BasePerson, related_name='relating_basepeople') Loading