Loading django/contrib/contenttypes/generic.py +17 −0 Original line number Diff line number Diff line Loading @@ -319,6 +319,23 @@ def create_generic_related_manager(superclass): '%s__exact' % object_id_field_name: instance._get_pk_val(), } def __call__(self, **kwargs): # We use **kwargs rather than a kwarg argument to enforce the # `manager='manager_name'` syntax. manager = getattr(self.model, kwargs.pop('manager')) manager_class = create_generic_related_manager(manager.__class__) return manager_class( model = self.model, instance = self.instance, symmetrical = self.symmetrical, source_col_name = self.source_col_name, target_col_name = self.target_col_name, content_type = self.content_type, content_type_field_name = self.content_type_field_name, object_id_field_name = self.object_id_field_name, prefetch_cache_name = self.prefetch_cache_name, ) def get_queryset(self): try: return self.instance._prefetched_objects_cache[self.prefetch_cache_name] Loading django/db/models/fields/related.py +108 −80 Original line number Diff line number Diff line Loading @@ -365,37 +365,7 @@ class ReverseSingleRelatedObjectDescriptor(six.with_metaclass(RenameRelatedObjec setattr(value, self.field.related.get_cache_name(), instance) class ForeignRelatedObjectsDescriptor(object): # This class provides the functionality that makes the related-object # managers available as attributes on a model class, for fields that have # multiple "remote" values and have a ForeignKey pointed at them by # some other model. In the example "poll.choice_set", the choice_set # attribute is a ForeignRelatedObjectsDescriptor instance. def __init__(self, related): self.related = related # RelatedObject instance def __get__(self, instance, instance_type=None): if instance is None: return self return self.related_manager_cls(instance) def __set__(self, instance, value): manager = self.__get__(instance) # If the foreign key can support nulls, then completely clear the related set. # Otherwise, just move the named objects into the set. if self.related.field.null: manager.clear() manager.add(*value) @cached_property def related_manager_cls(self): # Dynamically create a class that subclasses the related model's default # manager. superclass = self.related.model._default_manager.__class__ rel_field = self.related.field rel_model = self.related.model def create_foreign_related_manager(superclass, rel_field, rel_model): class RelatedManager(superclass): def __init__(self, instance): super(RelatedManager, self).__init__() Loading @@ -403,6 +373,13 @@ class ForeignRelatedObjectsDescriptor(object): self.core_filters = {'%s__exact' % rel_field.name: instance} self.model = rel_model def __call__(self, **kwargs): # We use **kwargs rather than a kwarg argument to enforce the # `manager='manager_name'` syntax. manager = getattr(self.model, kwargs.pop('manager')) manager_class = create_foreign_related_manager(manager.__class__, rel_field, rel_model) return manager_class(self.instance) def get_queryset(self): try: return self.instance._prefetched_objects_cache[rel_field.related_query_name()] Loading Loading @@ -474,6 +451,40 @@ class ForeignRelatedObjectsDescriptor(object): return RelatedManager class ForeignRelatedObjectsDescriptor(object): # This class provides the functionality that makes the related-object # managers available as attributes on a model class, for fields that have # multiple "remote" values and have a ForeignKey pointed at them by # some other model. In the example "poll.choice_set", the choice_set # attribute is a ForeignRelatedObjectsDescriptor instance. def __init__(self, related): self.related = related # RelatedObject instance def __get__(self, instance, instance_type=None): if instance is None: return self return self.related_manager_cls(instance) def __set__(self, instance, value): manager = self.__get__(instance) # If the foreign key can support nulls, then completely clear the related set. # Otherwise, just move the named objects into the set. if self.related.field.null: manager.clear() manager.add(*value) @cached_property def related_manager_cls(self): # Dynamically create a class that subclasses the related model's default # manager. return create_foreign_related_manager( self.related.model._default_manager.__class__, self.related.field, self.related.model, ) def create_many_related_manager(superclass, rel): """Creates a manager that subclasses 'superclass' (which is a Manager) and adds behavior for many-to-many related objects.""" Loading Loading @@ -513,6 +524,23 @@ def create_many_related_manager(superclass, rel): "a many-to-many relationship can be used." % instance.__class__.__name__) def __call__(self, **kwargs): # We use **kwargs rather than a kwarg argument to enforce the # `manager='manager_name'` syntax. manager = getattr(self.model, kwargs.pop('manager')) manager_class = create_many_related_manager(manager.__class__, rel) return manager_class( model=self.model, query_field_name=self.query_field_name, instance=self.instance, symmetrical=self.symmetrical, source_field_name=self.source_field_name, target_field_name=self.target_field_name, reverse=self.reverse, through=self.through, prefetch_cache_name=self.prefetch_cache_name, ) def get_queryset(self): try: return self.instance._prefetched_objects_cache[self.prefetch_cache_name] Loading docs/releases/1.7.txt +6 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,12 @@ The :meth:`QuerySet.as_manager() <django.db.models.query.QuerySet.as_manager>` class method has been added to :ref:`create Manager with QuerySet methods <create-manager-with-queryset-methods>`. Using a custom manager when traversing reverse relations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is now possible to :ref:`specify a custom manager <using-custom-reverse-manager>` when traversing a reverse relationship. Admin shortcuts support time zones ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading docs/topics/db/queries.txt +25 −0 Original line number Diff line number Diff line Loading @@ -1136,6 +1136,31 @@ above example code would look like this:: >>> b.entries.filter(headline__contains='Lennon') >>> b.entries.count() .. _using-custom-reverse-manager: Using a custom reverse manager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. versionadded:: 1.7 By default the :class:`~django.db.models.fields.related.RelatedManager` used for reverse relations is a subclass of the :ref:`default manager <manager-names>` for that model. If you would like to specify a different manager for a given query you can use the following syntax:: from django.db import models class Entry(models.Model): #... objects = models.Manager() # Default Manager entries = EntryManager() # Custom Manager >>> b = Blog.objects.get(id=1) >>> b.entry_set(manager='entries').all() Additional methods to handle related objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In addition to the :class:`~django.db.models.query.QuerySet` methods defined in "Retrieving objects" above, the :class:`~django.db.models.ForeignKey` :class:`~django.db.models.Manager` has additional methods used to handle the Loading tests/custom_managers/models.py +20 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ returns. from __future__ import unicode_literals from django.contrib.contenttypes import generic from django.db import models from django.utils.encoding import python_2_unicode_compatible Loading Loading @@ -63,12 +64,28 @@ class BaseCustomManager(models.Manager): CustomManager = BaseCustomManager.from_queryset(CustomQuerySet) class FunPeopleManager(models.Manager): def get_queryset(self): return super(FunPeopleManager, self).get_queryset().filter(fun=True) class BoringPeopleManager(models.Manager): def get_queryset(self): return super(BoringPeopleManager, self).get_queryset().filter(fun=False) @python_2_unicode_compatible class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) fun = models.BooleanField(default=False) favorite_book = models.ForeignKey('Book', null=True, related_name='favorite_books') favorite_thing_type = models.ForeignKey('contenttypes.ContentType', null=True) favorite_thing_id = models.IntegerField(null=True) favorite_thing = generic.GenericForeignKey('favorite_thing_type', 'favorite_thing_id') objects = PersonManager() fun_people = FunPeopleManager() boring_people = BoringPeopleManager() custom_queryset_default_manager = CustomQuerySet.as_manager() custom_queryset_custom_manager = CustomManager('hello') Loading @@ -84,6 +101,9 @@ class Book(models.Model): published_objects = PublishedBookManager() authors = models.ManyToManyField(Person, related_name='books') favorite_things = generic.GenericRelation(Person, content_type_field='favorite_thing_type', object_id_field='favorite_thing_id') def __str__(self): return self.title Loading Loading
django/contrib/contenttypes/generic.py +17 −0 Original line number Diff line number Diff line Loading @@ -319,6 +319,23 @@ def create_generic_related_manager(superclass): '%s__exact' % object_id_field_name: instance._get_pk_val(), } def __call__(self, **kwargs): # We use **kwargs rather than a kwarg argument to enforce the # `manager='manager_name'` syntax. manager = getattr(self.model, kwargs.pop('manager')) manager_class = create_generic_related_manager(manager.__class__) return manager_class( model = self.model, instance = self.instance, symmetrical = self.symmetrical, source_col_name = self.source_col_name, target_col_name = self.target_col_name, content_type = self.content_type, content_type_field_name = self.content_type_field_name, object_id_field_name = self.object_id_field_name, prefetch_cache_name = self.prefetch_cache_name, ) def get_queryset(self): try: return self.instance._prefetched_objects_cache[self.prefetch_cache_name] Loading
django/db/models/fields/related.py +108 −80 Original line number Diff line number Diff line Loading @@ -365,37 +365,7 @@ class ReverseSingleRelatedObjectDescriptor(six.with_metaclass(RenameRelatedObjec setattr(value, self.field.related.get_cache_name(), instance) class ForeignRelatedObjectsDescriptor(object): # This class provides the functionality that makes the related-object # managers available as attributes on a model class, for fields that have # multiple "remote" values and have a ForeignKey pointed at them by # some other model. In the example "poll.choice_set", the choice_set # attribute is a ForeignRelatedObjectsDescriptor instance. def __init__(self, related): self.related = related # RelatedObject instance def __get__(self, instance, instance_type=None): if instance is None: return self return self.related_manager_cls(instance) def __set__(self, instance, value): manager = self.__get__(instance) # If the foreign key can support nulls, then completely clear the related set. # Otherwise, just move the named objects into the set. if self.related.field.null: manager.clear() manager.add(*value) @cached_property def related_manager_cls(self): # Dynamically create a class that subclasses the related model's default # manager. superclass = self.related.model._default_manager.__class__ rel_field = self.related.field rel_model = self.related.model def create_foreign_related_manager(superclass, rel_field, rel_model): class RelatedManager(superclass): def __init__(self, instance): super(RelatedManager, self).__init__() Loading @@ -403,6 +373,13 @@ class ForeignRelatedObjectsDescriptor(object): self.core_filters = {'%s__exact' % rel_field.name: instance} self.model = rel_model def __call__(self, **kwargs): # We use **kwargs rather than a kwarg argument to enforce the # `manager='manager_name'` syntax. manager = getattr(self.model, kwargs.pop('manager')) manager_class = create_foreign_related_manager(manager.__class__, rel_field, rel_model) return manager_class(self.instance) def get_queryset(self): try: return self.instance._prefetched_objects_cache[rel_field.related_query_name()] Loading Loading @@ -474,6 +451,40 @@ class ForeignRelatedObjectsDescriptor(object): return RelatedManager class ForeignRelatedObjectsDescriptor(object): # This class provides the functionality that makes the related-object # managers available as attributes on a model class, for fields that have # multiple "remote" values and have a ForeignKey pointed at them by # some other model. In the example "poll.choice_set", the choice_set # attribute is a ForeignRelatedObjectsDescriptor instance. def __init__(self, related): self.related = related # RelatedObject instance def __get__(self, instance, instance_type=None): if instance is None: return self return self.related_manager_cls(instance) def __set__(self, instance, value): manager = self.__get__(instance) # If the foreign key can support nulls, then completely clear the related set. # Otherwise, just move the named objects into the set. if self.related.field.null: manager.clear() manager.add(*value) @cached_property def related_manager_cls(self): # Dynamically create a class that subclasses the related model's default # manager. return create_foreign_related_manager( self.related.model._default_manager.__class__, self.related.field, self.related.model, ) def create_many_related_manager(superclass, rel): """Creates a manager that subclasses 'superclass' (which is a Manager) and adds behavior for many-to-many related objects.""" Loading Loading @@ -513,6 +524,23 @@ def create_many_related_manager(superclass, rel): "a many-to-many relationship can be used." % instance.__class__.__name__) def __call__(self, **kwargs): # We use **kwargs rather than a kwarg argument to enforce the # `manager='manager_name'` syntax. manager = getattr(self.model, kwargs.pop('manager')) manager_class = create_many_related_manager(manager.__class__, rel) return manager_class( model=self.model, query_field_name=self.query_field_name, instance=self.instance, symmetrical=self.symmetrical, source_field_name=self.source_field_name, target_field_name=self.target_field_name, reverse=self.reverse, through=self.through, prefetch_cache_name=self.prefetch_cache_name, ) def get_queryset(self): try: return self.instance._prefetched_objects_cache[self.prefetch_cache_name] Loading
docs/releases/1.7.txt +6 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,12 @@ The :meth:`QuerySet.as_manager() <django.db.models.query.QuerySet.as_manager>` class method has been added to :ref:`create Manager with QuerySet methods <create-manager-with-queryset-methods>`. Using a custom manager when traversing reverse relations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is now possible to :ref:`specify a custom manager <using-custom-reverse-manager>` when traversing a reverse relationship. Admin shortcuts support time zones ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading
docs/topics/db/queries.txt +25 −0 Original line number Diff line number Diff line Loading @@ -1136,6 +1136,31 @@ above example code would look like this:: >>> b.entries.filter(headline__contains='Lennon') >>> b.entries.count() .. _using-custom-reverse-manager: Using a custom reverse manager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. versionadded:: 1.7 By default the :class:`~django.db.models.fields.related.RelatedManager` used for reverse relations is a subclass of the :ref:`default manager <manager-names>` for that model. If you would like to specify a different manager for a given query you can use the following syntax:: from django.db import models class Entry(models.Model): #... objects = models.Manager() # Default Manager entries = EntryManager() # Custom Manager >>> b = Blog.objects.get(id=1) >>> b.entry_set(manager='entries').all() Additional methods to handle related objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In addition to the :class:`~django.db.models.query.QuerySet` methods defined in "Retrieving objects" above, the :class:`~django.db.models.ForeignKey` :class:`~django.db.models.Manager` has additional methods used to handle the Loading
tests/custom_managers/models.py +20 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ returns. from __future__ import unicode_literals from django.contrib.contenttypes import generic from django.db import models from django.utils.encoding import python_2_unicode_compatible Loading Loading @@ -63,12 +64,28 @@ class BaseCustomManager(models.Manager): CustomManager = BaseCustomManager.from_queryset(CustomQuerySet) class FunPeopleManager(models.Manager): def get_queryset(self): return super(FunPeopleManager, self).get_queryset().filter(fun=True) class BoringPeopleManager(models.Manager): def get_queryset(self): return super(BoringPeopleManager, self).get_queryset().filter(fun=False) @python_2_unicode_compatible class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) fun = models.BooleanField(default=False) favorite_book = models.ForeignKey('Book', null=True, related_name='favorite_books') favorite_thing_type = models.ForeignKey('contenttypes.ContentType', null=True) favorite_thing_id = models.IntegerField(null=True) favorite_thing = generic.GenericForeignKey('favorite_thing_type', 'favorite_thing_id') objects = PersonManager() fun_people = FunPeopleManager() boring_people = BoringPeopleManager() custom_queryset_default_manager = CustomQuerySet.as_manager() custom_queryset_custom_manager = CustomManager('hello') Loading @@ -84,6 +101,9 @@ class Book(models.Model): published_objects = PublishedBookManager() authors = models.ManyToManyField(Person, related_name='books') favorite_things = generic.GenericRelation(Person, content_type_field='favorite_thing_type', object_id_field='favorite_thing_id') def __str__(self): return self.title Loading