From 593810a5014ecaa28215839fb42f03df44a069d0 Mon Sep 17 00:00:00 2001 From: Jacob Kaplan-Moss Date: Tue, 5 Aug 2008 16:13:28 +0000 Subject: [PATCH] Fixed #7904: added support for a "use_for_related_fields" property on managers. If True, the manager will be used for related object lookups instead of the "bare" QuerySet introduced bu [8107]. Patch from Justin Bronn. git-svn-id: http://code.djangoproject.com/svn/django/trunk@8212 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/fields/related.py | 9 ++++++++- docs/model-api.txt | 11 +++++++++++ .../reverse_single_related/models.py | 17 ++++++++++++++--- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index e8141986da..ab2b9a6c5e 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -239,7 +239,14 @@ class ReverseSingleRelatedObjectDescriptor(object): params = {'%s__pk' % self.field.rel.field_name: val} else: params = {'%s__exact' % self.field.rel.field_name: val} - rel_obj = QuerySet(self.field.rel.to).get(**params) + + # If the related manager indicates that it should be used for + # related fields, respect that. + rel_mgr = self.field.rel.to._default_manager + if getattr(rel_mgr, 'use_for_related_fields', False): + rel_obj = rel_mgr.get(**params) + else: + rel_obj = QuerySet(self.field.rel.to).get(**params) setattr(instance, cache_name, rel_obj) return rel_obj diff --git a/docs/model-api.txt b/docs/model-api.txt index f624e68844..b6a446b50e 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -1507,6 +1507,17 @@ good idea to be careful in your choice of default manager, in order to avoid a situation where overriding of ``get_query_set()`` results in an inability to retrieve objects you'd like to work with. +Using managers for related object access +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, Django uses a "bare" (i.e. default) manager when accessing related +objects (i.e. ``choice.poll``). If this default isn't appropriate for your default manager, you can force Django to use a custom manager for related object attributes by giving it a ``use_for_related_fields`` property:: + + class MyManager(models.Manager):: + use_for_related_fields = True + + ... + Model methods ============= diff --git a/tests/regressiontests/reverse_single_related/models.py b/tests/regressiontests/reverse_single_related/models.py index c6bbbebd3d..b2b75392aa 100644 --- a/tests/regressiontests/reverse_single_related/models.py +++ b/tests/regressiontests/reverse_single_related/models.py @@ -26,7 +26,7 @@ __test__ = {'API_TESTS':""" >>> private_source = Source.objects.create(is_public=False) >>> private_item = Item.objects.create(source=private_source) -Only one source is available via all() due to the custom default manager. +# Only one source is available via all() due to the custom default manager. >>> Source.objects.all() [] @@ -34,10 +34,21 @@ Only one source is available via all() due to the custom default manager. >>> public_item.source -Make sure that an item can still access its related source even if the default -manager doesn't normally allow it. +# Make sure that an item can still access its related source even if the default +# manager doesn't normally allow it. >>> private_item.source +# If the manager is marked "use_for_related_fields", it'll get used instead +# of the "bare" queryset. Usually you'd define this as a property on the class, +# but this approximates that in a way that's easier in tests. + +>>> Source.objects.use_for_related_fields = True +>>> private_item = Item.objects.get(pk=private_item.pk) +>>> private_item.source +Traceback (most recent call last): + ... +DoesNotExist: Source matching query does not exist. + """}