diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index eee2ecf..5bf75d7 100644
a
|
b
|
from django.db.models.related import RelatedObject
|
7 | 7 | from django.db.models.query import QuerySet |
8 | 8 | from django.db.models.query_utils import QueryWrapper |
9 | 9 | from django.db.models.deletion import CASCADE |
| 10 | from django.db.models.manager import ManagerDescriptor |
10 | 11 | from django.utils.encoding import smart_unicode |
11 | 12 | from django.utils.translation import ugettext_lazy as _, string_concat |
12 | 13 | from django.utils.functional import curry |
… |
… |
class ForeignRelatedObjectsDescriptor(object):
|
386 | 387 | if instance is None: |
387 | 388 | return self |
388 | 389 | |
389 | | return self.create_manager(instance, |
| 390 | def _other_fk_managers(manager): |
| 391 | """ |
| 392 | Selects a manager from the list of the model's managers, useful |
| 393 | in the case of choosing a manager which is not the default, in a reverse relation. |
| 394 | """ |
| 395 | if manager in self.related.model.__dict__ and isinstance(self.related.model.__dict__.get(manager, None), ManagerDescriptor): |
| 396 | return self.create_manager(instance, self.related.model.__dict__.get(manager).manager.__class__) |
| 397 | else: |
| 398 | raise AttributeError("Manager %s does not exist" % manager) |
| 399 | |
| 400 | manager = self.create_manager(instance, |
390 | 401 | self.related.model._default_manager.__class__) |
| 402 | manager.managers = _other_fk_managers |
| 403 | return manager |
391 | 404 | |
392 | 405 | def __set__(self, instance, value): |
393 | 406 | if instance is None: |
… |
… |
class ManyRelatedObjectsDescriptor(object):
|
671 | 684 | # model's default manager. |
672 | 685 | rel_model = self.related.model |
673 | 686 | superclass = rel_model._default_manager.__class__ |
| 687 | |
674 | 688 | RelatedManager = create_many_related_manager(superclass, self.related.field.rel) |
675 | 689 | |
676 | 690 | manager = RelatedManager( |
… |
… |
class ManyRelatedObjectsDescriptor(object):
|
684 | 698 | through=self.related.field.rel.through, |
685 | 699 | ) |
686 | 700 | |
| 701 | def _other_m2m_managers(manager): |
| 702 | """ |
| 703 | Selects a manager from the list of the model's managers, useful |
| 704 | in the case of choosing a manager which is not the default, in a reverse relation. |
| 705 | """ |
| 706 | if manager in self.related.model.__dict__ and isinstance(self.related.model.__dict__.get(manager, None), ManagerDescriptor): |
| 707 | return self.create_many_related_manager(self.related.model.__dict__.get(manager).manager.__class__, self.related.field.rel) |
| 708 | else: |
| 709 | raise AttributeError("Manager %s does not exist" % manager) |
| 710 | |
| 711 | manager.managers = _other_m2m_managers |
687 | 712 | return manager |
688 | 713 | |
689 | 714 | def __set__(self, instance, value): |
diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt
index 23ed124..26e502f 100644
a
|
b
|
Each "reverse" operation described in this section has an immediate effect on
|
1036 | 1036 | the database. Every addition, creation and deletion is immediately and |
1037 | 1037 | automatically saved to the database. |
1038 | 1038 | |
| 1039 | The ``entry_set`` notation, returns the default ``Manager`` defined for the |
| 1040 | ``Entry`` model, if you want to choose a custom manager, use the ``managers()`` |
| 1041 | method of ``entry_set``. For example:: |
| 1042 | |
| 1043 | b = Blog.objects.get(id=1) |
| 1044 | # Selects the custom_manager attribute, defined on Entry |
| 1045 | b.entry_set.managers('custom_manager') |
| 1046 | |
1039 | 1047 | .. _m2m-reverse-relationships: |
1040 | 1048 | |
1041 | 1049 | Many-to-many relationships |
… |
… |
An example makes this easier to understand::
|
1062 | 1070 | Like ``ForeignKey``, ``ManyToManyField`` can specify ``related_name``. In the |
1063 | 1071 | above example, if the ``ManyToManyField`` in ``Entry`` had specified |
1064 | 1072 | ``related_name='entries'``, then each ``Author`` instance would have an |
1065 | | ``entries`` attribute instead of ``entry_set``. |
| 1073 | ``entries`` attribute instead of ``entry_set``. The ``entries`` attribute, |
| 1074 | also has a ``managers()`` method to select custom managers. For example:: |
| 1075 | |
| 1076 | b = Author.objects.get(id=5) |
| 1077 | # Selects the custom_manager attribute, defined on Entry |
| 1078 | b.entries.managers('custom_manager') |
| 1079 | |
1066 | 1080 | |
1067 | 1081 | One-to-one relationships |
1068 | 1082 | ------------------------ |
diff --git a/tests/modeltests/custom_managers/models.py b/tests/modeltests/custom_managers/models.py
index 1052552..89a665c 100644
a
|
b
|
class FastCarManager(models.Manager):
|
50 | 50 | |
51 | 51 | class Car(models.Model): |
52 | 52 | name = models.CharField(max_length=10) |
| 53 | manufacturer = models.ForeignKey('Manufacturer') |
53 | 54 | mileage = models.IntegerField() |
54 | 55 | top_speed = models.IntegerField(help_text="In miles per hour.") |
55 | 56 | cars = models.Manager() |
… |
… |
class Car(models.Model):
|
57 | 58 | |
58 | 59 | def __unicode__(self): |
59 | 60 | return self.name |
| 61 | |
| 62 | class Manufacturer(models.Model): |
| 63 | name = models.CharField(max_length=10) |
| 64 | country = models.CharField(max_length=20) |
diff --git a/tests/modeltests/custom_managers/tests.py b/tests/modeltests/custom_managers/tests.py
index 8721e9a..1ad41e8 100644
a
|
b
|
|
1 | 1 | from django.test import TestCase |
2 | 2 | |
3 | | from models import Person, Book, Car, PersonManager, PublishedBookManager |
| 3 | from models import Person, Book, Car, Manufacturer, PersonManager, PublishedBookManager |
4 | 4 | |
5 | 5 | |
6 | 6 | class CustomManagerTests(TestCase): |
… |
… |
class CustomManagerTests(TestCase):
|
40 | 40 | lambda b: b.title |
41 | 41 | ) |
42 | 42 | |
43 | | c1 = Car.cars.create(name="Corvette", mileage=21, top_speed=180) |
44 | | c2 = Car.cars.create(name="Neon", mileage=31, top_speed=100) |
| 43 | chevy = Manufacturer.objects.create(name="Chevrolet", country="USA") |
| 44 | dodge = Manufacturer.objects.create(name="Dodge", country="USA") |
| 45 | |
| 46 | c1 = Car.cars.create(name="Corvette", mileage=21, top_speed=180, manufacturer=chevy) |
| 47 | c2 = Car.cars.create(name="Neon", mileage=31, top_speed=100, manufacturer=dodge) |
| 48 | c3 = Car.cars.create(name="Viper", mileage=14, top_speed=200, manufacturer=dodge) |
45 | 49 | |
46 | 50 | self.assertQuerysetEqual( |
47 | 51 | Car.cars.order_by("name"), [ |
48 | 52 | "Corvette", |
49 | 53 | "Neon", |
| 54 | "Viper" |
50 | 55 | ], |
51 | 56 | lambda c: c.name |
52 | 57 | ) |
… |
… |
class CustomManagerTests(TestCase):
|
54 | 59 | self.assertQuerysetEqual( |
55 | 60 | Car.fast_cars.all(), [ |
56 | 61 | "Corvette", |
| 62 | "Viper", |
57 | 63 | ], |
58 | 64 | lambda c: c.name |
59 | 65 | ) |
… |
… |
class CustomManagerTests(TestCase):
|
66 | 72 | Car._default_manager.order_by("name"), [ |
67 | 73 | "Corvette", |
68 | 74 | "Neon", |
| 75 | "Viper", |
| 76 | ], |
| 77 | lambda c: c.name |
| 78 | ) |
| 79 | |
| 80 | #Choosing a custom manager in a reverse relation |
| 81 | self.assertQuerysetEqual( |
| 82 | dodge.car_set.managers('fast_cars').all(), [ |
| 83 | "Viper", |
69 | 84 | ], |
70 | 85 | lambda c: c.name |
71 | 86 | ) |