1 | diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
|
---|
2 | index eee2ecf..5bf75d7 100644
|
---|
3 | --- a/django/db/models/fields/related.py
|
---|
4 | +++ b/django/db/models/fields/related.py
|
---|
5 | @@ -7,6 +7,7 @@ from django.db.models.related import RelatedObject
|
---|
6 | from django.db.models.query import QuerySet
|
---|
7 | from django.db.models.query_utils import QueryWrapper
|
---|
8 | from django.db.models.deletion import CASCADE
|
---|
9 | +from django.db.models.manager import ManagerDescriptor
|
---|
10 | from django.utils.encoding import smart_unicode
|
---|
11 | from django.utils.translation import ugettext_lazy as _, string_concat
|
---|
12 | from django.utils.functional import curry
|
---|
13 | @@ -386,8 +387,20 @@ class ForeignRelatedObjectsDescriptor(object):
|
---|
14 | if instance is None:
|
---|
15 | return self
|
---|
16 |
|
---|
17 | - return self.create_manager(instance,
|
---|
18 | + def _other_fk_managers(manager):
|
---|
19 | + """
|
---|
20 | + Selects a manager from the list of the model's managers, useful
|
---|
21 | + in the case of choosing a manager which is not the default, in a reverse relation.
|
---|
22 | + """
|
---|
23 | + if manager in self.related.model.__dict__ and isinstance(self.related.model.__dict__.get(manager, None), ManagerDescriptor):
|
---|
24 | + return self.create_manager(instance, self.related.model.__dict__.get(manager).manager.__class__)
|
---|
25 | + else:
|
---|
26 | + raise AttributeError("Manager %s does not exist" % manager)
|
---|
27 | +
|
---|
28 | + manager = self.create_manager(instance,
|
---|
29 | self.related.model._default_manager.__class__)
|
---|
30 | + manager.managers = _other_fk_managers
|
---|
31 | + return manager
|
---|
32 |
|
---|
33 | def __set__(self, instance, value):
|
---|
34 | if instance is None:
|
---|
35 | @@ -671,6 +684,7 @@ class ManyRelatedObjectsDescriptor(object):
|
---|
36 | # model's default manager.
|
---|
37 | rel_model = self.related.model
|
---|
38 | superclass = rel_model._default_manager.__class__
|
---|
39 | +
|
---|
40 | RelatedManager = create_many_related_manager(superclass, self.related.field.rel)
|
---|
41 |
|
---|
42 | manager = RelatedManager(
|
---|
43 | @@ -684,6 +698,17 @@ class ManyRelatedObjectsDescriptor(object):
|
---|
44 | through=self.related.field.rel.through,
|
---|
45 | )
|
---|
46 |
|
---|
47 | + def _other_m2m_managers(manager):
|
---|
48 | + """
|
---|
49 | + Selects a manager from the list of the model's managers, useful
|
---|
50 | + in the case of choosing a manager which is not the default, in a reverse relation.
|
---|
51 | + """
|
---|
52 | + if manager in self.related.model.__dict__ and isinstance(self.related.model.__dict__.get(manager, None), ManagerDescriptor):
|
---|
53 | + return self.create_many_related_manager(self.related.model.__dict__.get(manager).manager.__class__, self.related.field.rel)
|
---|
54 | + else:
|
---|
55 | + raise AttributeError("Manager %s does not exist" % manager)
|
---|
56 | +
|
---|
57 | + manager.managers = _other_m2m_managers
|
---|
58 | return manager
|
---|
59 |
|
---|
60 | def __set__(self, instance, value):
|
---|
61 | diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt
|
---|
62 | index 23ed124..26e502f 100644
|
---|
63 | --- a/docs/topics/db/queries.txt
|
---|
64 | +++ b/docs/topics/db/queries.txt
|
---|
65 | @@ -1036,6 +1036,14 @@ Each "reverse" operation described in this section has an immediate effect on
|
---|
66 | the database. Every addition, creation and deletion is immediately and
|
---|
67 | automatically saved to the database.
|
---|
68 |
|
---|
69 | +The ``entry_set`` notation, returns the default ``Manager`` defined for the
|
---|
70 | +``Entry`` model, if you want to choose a custom manager, use the ``managers()``
|
---|
71 | +method of ``entry_set``. For example::
|
---|
72 | +
|
---|
73 | + b = Blog.objects.get(id=1)
|
---|
74 | + # Selects the custom_manager attribute, defined on Entry
|
---|
75 | + b.entry_set.managers('custom_manager')
|
---|
76 | +
|
---|
77 | .. _m2m-reverse-relationships:
|
---|
78 |
|
---|
79 | Many-to-many relationships
|
---|
80 | @@ -1062,7 +1070,13 @@ An example makes this easier to understand::
|
---|
81 | Like ``ForeignKey``, ``ManyToManyField`` can specify ``related_name``. In the
|
---|
82 | above example, if the ``ManyToManyField`` in ``Entry`` had specified
|
---|
83 | ``related_name='entries'``, then each ``Author`` instance would have an
|
---|
84 | -``entries`` attribute instead of ``entry_set``.
|
---|
85 | +``entries`` attribute instead of ``entry_set``. The ``entries`` attribute,
|
---|
86 | +also has a ``managers()`` method to select custom managers. For example::
|
---|
87 | +
|
---|
88 | + b = Author.objects.get(id=5)
|
---|
89 | + # Selects the custom_manager attribute, defined on Entry
|
---|
90 | + b.entries.managers('custom_manager')
|
---|
91 | +
|
---|
92 |
|
---|
93 | One-to-one relationships
|
---|
94 | ------------------------
|
---|
95 | diff --git a/tests/modeltests/custom_managers/models.py b/tests/modeltests/custom_managers/models.py
|
---|
96 | index 1052552..89a665c 100644
|
---|
97 | --- a/tests/modeltests/custom_managers/models.py
|
---|
98 | +++ b/tests/modeltests/custom_managers/models.py
|
---|
99 | @@ -50,6 +50,7 @@ class FastCarManager(models.Manager):
|
---|
100 |
|
---|
101 | class Car(models.Model):
|
---|
102 | name = models.CharField(max_length=10)
|
---|
103 | + manufacturer = models.ForeignKey('Manufacturer')
|
---|
104 | mileage = models.IntegerField()
|
---|
105 | top_speed = models.IntegerField(help_text="In miles per hour.")
|
---|
106 | cars = models.Manager()
|
---|
107 | @@ -57,3 +58,7 @@ class Car(models.Model):
|
---|
108 |
|
---|
109 | def __unicode__(self):
|
---|
110 | return self.name
|
---|
111 | +
|
---|
112 | +class Manufacturer(models.Model):
|
---|
113 | + name = models.CharField(max_length=10)
|
---|
114 | + country = models.CharField(max_length=20)
|
---|
115 | diff --git a/tests/modeltests/custom_managers/tests.py b/tests/modeltests/custom_managers/tests.py
|
---|
116 | index 8721e9a..1ad41e8 100644
|
---|
117 | --- a/tests/modeltests/custom_managers/tests.py
|
---|
118 | +++ b/tests/modeltests/custom_managers/tests.py
|
---|
119 | @@ -1,6 +1,6 @@
|
---|
120 | from django.test import TestCase
|
---|
121 |
|
---|
122 | -from models import Person, Book, Car, PersonManager, PublishedBookManager
|
---|
123 | +from models import Person, Book, Car, Manufacturer, PersonManager, PublishedBookManager
|
---|
124 |
|
---|
125 |
|
---|
126 | class CustomManagerTests(TestCase):
|
---|
127 | @@ -40,13 +40,18 @@ class CustomManagerTests(TestCase):
|
---|
128 | lambda b: b.title
|
---|
129 | )
|
---|
130 |
|
---|
131 | - c1 = Car.cars.create(name="Corvette", mileage=21, top_speed=180)
|
---|
132 | - c2 = Car.cars.create(name="Neon", mileage=31, top_speed=100)
|
---|
133 | + chevy = Manufacturer.objects.create(name="Chevrolet", country="USA")
|
---|
134 | + dodge = Manufacturer.objects.create(name="Dodge", country="USA")
|
---|
135 | +
|
---|
136 | + c1 = Car.cars.create(name="Corvette", mileage=21, top_speed=180, manufacturer=chevy)
|
---|
137 | + c2 = Car.cars.create(name="Neon", mileage=31, top_speed=100, manufacturer=dodge)
|
---|
138 | + c3 = Car.cars.create(name="Viper", mileage=14, top_speed=200, manufacturer=dodge)
|
---|
139 |
|
---|
140 | self.assertQuerysetEqual(
|
---|
141 | Car.cars.order_by("name"), [
|
---|
142 | "Corvette",
|
---|
143 | "Neon",
|
---|
144 | + "Viper"
|
---|
145 | ],
|
---|
146 | lambda c: c.name
|
---|
147 | )
|
---|
148 | @@ -54,6 +59,7 @@ class CustomManagerTests(TestCase):
|
---|
149 | self.assertQuerysetEqual(
|
---|
150 | Car.fast_cars.all(), [
|
---|
151 | "Corvette",
|
---|
152 | + "Viper",
|
---|
153 | ],
|
---|
154 | lambda c: c.name
|
---|
155 | )
|
---|
156 | @@ -66,6 +72,15 @@ class CustomManagerTests(TestCase):
|
---|
157 | Car._default_manager.order_by("name"), [
|
---|
158 | "Corvette",
|
---|
159 | "Neon",
|
---|
160 | + "Viper",
|
---|
161 | + ],
|
---|
162 | + lambda c: c.name
|
---|
163 | + )
|
---|
164 | +
|
---|
165 | + #Choosing a custom manager in a reverse relation
|
---|
166 | + self.assertQuerysetEqual(
|
---|
167 | + dodge.car_set.managers('fast_cars').all(), [
|
---|
168 | + "Viper",
|
---|
169 | ],
|
---|
170 | lambda c: c.name
|
---|
171 | )
|
---|