Ticket #3871: 3871-patch-with-docs

File 3871-patch-with-docs, 7.0 KB (added by v1v3kn, 12 years ago)

updated patch with docs

Line 
1diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
2index 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):
61diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt
62index 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 ------------------------
95diff --git a/tests/modeltests/custom_managers/models.py b/tests/modeltests/custom_managers/models.py
96index 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)
115diff --git a/tests/modeltests/custom_managers/tests.py b/tests/modeltests/custom_managers/tests.py
116index 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 )
Back to Top