Loading django/db/models/fields/related.py +7 −0 Original line number Diff line number Diff line Loading @@ -299,6 +299,13 @@ class RelatedField(Field): } self.remote_field.related_name = related_name if self.remote_field.related_query_name: related_query_name = force_text(self.remote_field.related_query_name) % { 'class': cls.__name__.lower(), 'app_label': cls._meta.app_label.lower(), } self.remote_field.related_query_name = related_query_name def resolve_related_class(model, related, field): field.remote_field.model = related field.do_related_class(related, model) Loading docs/ref/models/fields.txt +3 −0 Original line number Diff line number Diff line Loading @@ -1344,6 +1344,9 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in # That's now the name of the reverse filter Article.objects.filter(tag__name="important") Like :attr:`related_name`, ``related_query_name`` supports app label and class interpolation via :ref:`some special syntax <abstract-related-name>`. .. attribute:: ForeignKey.to_field The field on the related object that the relation is to. By default, Django Loading docs/releases/1.10.txt +4 −0 Original line number Diff line number Diff line Loading @@ -268,6 +268,10 @@ Models * :meth:`QuerySet.in_bulk() <django.db.models.query.QuerySet.in_bulk>` may be called without any arguments to return all objects in the queryset. * :attr:`~django.db.models.ForeignKey.related_query_name` now supports app label and class interpolation using the ``'%(app_label)s'`` and ``'%(class)s'`` strings. Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ Loading docs/topics/db/models.txt +35 −18 Original line number Diff line number Diff line Loading @@ -967,18 +967,23 @@ the same database table, which is almost certainly not what you want. .. _abstract-related-name: Be careful with ``related_name`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you are using the :attr:`~django.db.models.ForeignKey.related_name` attribute on a ``ForeignKey`` or ``ManyToManyField``, you must always specify a *unique* reverse name for the field. This would normally cause a problem in abstract base classes, since the fields on this class are included into each of the child classes, with exactly the same values for the attributes (including :attr:`~django.db.models.ForeignKey.related_name`) each time. Be careful with ``related_name`` and ``related_query_name`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To work around this problem, when you are using :attr:`~django.db.models.ForeignKey.related_name` in an abstract base class (only), part of the name should contain ``'%(app_label)s'`` and ``'%(class)s'``. If you are using :attr:`~django.db.models.ForeignKey.related_name` or :attr:`~django.db.models.ForeignKey.related_query_name` on a ``ForeignKey`` or ``ManyToManyField``, you must always specify a *unique* reverse name and query name for the field. This would normally cause a problem in abstract base classes, since the fields on this class are included into each of the child classes, with exactly the same values for the attributes (including :attr:`~django.db.models.ForeignKey.related_name` and :attr:`~django.db.models.ForeignKey.related_query_name`) each time. To work around this problem, when you are using :attr:`~django.db.models.ForeignKey.related_name` or :attr:`~django.db.models.ForeignKey.related_query_name` in an abstract base class (only), part of the value should contain ``'%(app_label)s'`` and ``'%(class)s'``. - ``'%(class)s'`` is replaced by the lower-cased name of the child class that the field is used in. Loading @@ -992,7 +997,11 @@ For example, given an app ``common/models.py``:: from django.db import models class Base(models.Model): m2m = models.ManyToManyField(OtherModel, related_name="%(app_label)s_%(class)s_related") m2m = models.ManyToManyField( OtherModel, related_name="%(app_label)s_%(class)s_related", related_query_name="%(app_label)s_%(class)ss", ) class Meta: abstract = True Loading @@ -1011,12 +1020,15 @@ Along with another app ``rare/models.py``:: pass The reverse name of the ``common.ChildA.m2m`` field will be ``common_childa_related``, while the reverse name of the ``common.ChildB.m2m`` field will be ``common_childb_related``, and finally the reverse name of the ``rare.ChildB.m2m`` field will be ``rare_childb_related``. It is up to you how you use the ``'%(class)s'`` and ``'%(app_label)s`` portion to construct your related name, but if you forget to use it, Django will raise errors when you perform system checks (or run :djadmin:`migrate`). ``common_childa_related`` and the reverse query name will be ``common_childas``. The reverse name of the ``common.ChildB.m2m`` field will be ``common_childb_related`` and the reverse query name will be ``common_childbs``. Finally, the reverse name of the ``rare.ChildB.m2m`` field will be ``rare_childb_related`` and the reverse query name will be ``rare_childbs``. It's up to you how you use the `'%(class)s'`` and ``'%(app_label)s`` portion to construct your related name or related query name but if you forget to use it, Django will raise errors when you perform system checks (or run :djadmin:`migrate`). If you don't specify a :attr:`~django.db.models.ForeignKey.related_name` attribute for a field in an abstract base class, the default reverse name will Loading @@ -1027,6 +1039,11 @@ attribute was omitted, the reverse name for the ``m2m`` field would be ``childa_set`` in the ``ChildA`` case and ``childb_set`` for the ``ChildB`` field. .. versionchanged:: 1.10 Interpolation of ``'%(app_label)s'`` and ``'%(class)s'`` for ``related_query_name`` was added. .. _multi-table-inheritance: Multi-table inheritance Loading tests/model_inheritance/models.py +6 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,12 @@ class Post(models.Model): @python_2_unicode_compatible class Attachment(models.Model): post = models.ForeignKey(Post, models.CASCADE, related_name='attached_%(class)s_set') post = models.ForeignKey( Post, models.CASCADE, related_name='attached_%(class)s_set', related_query_name='attached_%(app_label)s_%(class)ss', ) content = models.TextField() class Meta: Loading Loading
django/db/models/fields/related.py +7 −0 Original line number Diff line number Diff line Loading @@ -299,6 +299,13 @@ class RelatedField(Field): } self.remote_field.related_name = related_name if self.remote_field.related_query_name: related_query_name = force_text(self.remote_field.related_query_name) % { 'class': cls.__name__.lower(), 'app_label': cls._meta.app_label.lower(), } self.remote_field.related_query_name = related_query_name def resolve_related_class(model, related, field): field.remote_field.model = related field.do_related_class(related, model) Loading
docs/ref/models/fields.txt +3 −0 Original line number Diff line number Diff line Loading @@ -1344,6 +1344,9 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in # That's now the name of the reverse filter Article.objects.filter(tag__name="important") Like :attr:`related_name`, ``related_query_name`` supports app label and class interpolation via :ref:`some special syntax <abstract-related-name>`. .. attribute:: ForeignKey.to_field The field on the related object that the relation is to. By default, Django Loading
docs/releases/1.10.txt +4 −0 Original line number Diff line number Diff line Loading @@ -268,6 +268,10 @@ Models * :meth:`QuerySet.in_bulk() <django.db.models.query.QuerySet.in_bulk>` may be called without any arguments to return all objects in the queryset. * :attr:`~django.db.models.ForeignKey.related_query_name` now supports app label and class interpolation using the ``'%(app_label)s'`` and ``'%(class)s'`` strings. Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ Loading
docs/topics/db/models.txt +35 −18 Original line number Diff line number Diff line Loading @@ -967,18 +967,23 @@ the same database table, which is almost certainly not what you want. .. _abstract-related-name: Be careful with ``related_name`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you are using the :attr:`~django.db.models.ForeignKey.related_name` attribute on a ``ForeignKey`` or ``ManyToManyField``, you must always specify a *unique* reverse name for the field. This would normally cause a problem in abstract base classes, since the fields on this class are included into each of the child classes, with exactly the same values for the attributes (including :attr:`~django.db.models.ForeignKey.related_name`) each time. Be careful with ``related_name`` and ``related_query_name`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To work around this problem, when you are using :attr:`~django.db.models.ForeignKey.related_name` in an abstract base class (only), part of the name should contain ``'%(app_label)s'`` and ``'%(class)s'``. If you are using :attr:`~django.db.models.ForeignKey.related_name` or :attr:`~django.db.models.ForeignKey.related_query_name` on a ``ForeignKey`` or ``ManyToManyField``, you must always specify a *unique* reverse name and query name for the field. This would normally cause a problem in abstract base classes, since the fields on this class are included into each of the child classes, with exactly the same values for the attributes (including :attr:`~django.db.models.ForeignKey.related_name` and :attr:`~django.db.models.ForeignKey.related_query_name`) each time. To work around this problem, when you are using :attr:`~django.db.models.ForeignKey.related_name` or :attr:`~django.db.models.ForeignKey.related_query_name` in an abstract base class (only), part of the value should contain ``'%(app_label)s'`` and ``'%(class)s'``. - ``'%(class)s'`` is replaced by the lower-cased name of the child class that the field is used in. Loading @@ -992,7 +997,11 @@ For example, given an app ``common/models.py``:: from django.db import models class Base(models.Model): m2m = models.ManyToManyField(OtherModel, related_name="%(app_label)s_%(class)s_related") m2m = models.ManyToManyField( OtherModel, related_name="%(app_label)s_%(class)s_related", related_query_name="%(app_label)s_%(class)ss", ) class Meta: abstract = True Loading @@ -1011,12 +1020,15 @@ Along with another app ``rare/models.py``:: pass The reverse name of the ``common.ChildA.m2m`` field will be ``common_childa_related``, while the reverse name of the ``common.ChildB.m2m`` field will be ``common_childb_related``, and finally the reverse name of the ``rare.ChildB.m2m`` field will be ``rare_childb_related``. It is up to you how you use the ``'%(class)s'`` and ``'%(app_label)s`` portion to construct your related name, but if you forget to use it, Django will raise errors when you perform system checks (or run :djadmin:`migrate`). ``common_childa_related`` and the reverse query name will be ``common_childas``. The reverse name of the ``common.ChildB.m2m`` field will be ``common_childb_related`` and the reverse query name will be ``common_childbs``. Finally, the reverse name of the ``rare.ChildB.m2m`` field will be ``rare_childb_related`` and the reverse query name will be ``rare_childbs``. It's up to you how you use the `'%(class)s'`` and ``'%(app_label)s`` portion to construct your related name or related query name but if you forget to use it, Django will raise errors when you perform system checks (or run :djadmin:`migrate`). If you don't specify a :attr:`~django.db.models.ForeignKey.related_name` attribute for a field in an abstract base class, the default reverse name will Loading @@ -1027,6 +1039,11 @@ attribute was omitted, the reverse name for the ``m2m`` field would be ``childa_set`` in the ``ChildA`` case and ``childb_set`` for the ``ChildB`` field. .. versionchanged:: 1.10 Interpolation of ``'%(app_label)s'`` and ``'%(class)s'`` for ``related_query_name`` was added. .. _multi-table-inheritance: Multi-table inheritance Loading
tests/model_inheritance/models.py +6 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,12 @@ class Post(models.Model): @python_2_unicode_compatible class Attachment(models.Model): post = models.ForeignKey(Post, models.CASCADE, related_name='attached_%(class)s_set') post = models.ForeignKey( Post, models.CASCADE, related_name='attached_%(class)s_set', related_query_name='attached_%(app_label)s_%(class)ss', ) content = models.TextField() class Meta: Loading