This manager (contributed by Jeff Elmore) should be attached to a base model class in a model-inheritance tree. It allows queries on that base model to return heterogenous results of the actual proper subtypes, without any additional queries.
For instance, if you have a
Place model with subclasses
Bar, you may want to query all Places:
nearby_places = Place.objects.filter(location='here')
But when you iterate over
nearby_places, you’ll get only
instances back, even for objects that are “really”
If you attach an
Place, you can just call the
select_subclasses() method on the
InheritanceManager or any
QuerySet from it, and the resulting objects will be instances of
from model_utils.managers import InheritanceManager class Place(models.Model): # ... objects = InheritanceManager() class Restaurant(Place): # ... class Bar(Place): # ... nearby_places = Place.objects.filter(location='here').select_subclasses() for place in nearby_places: # "place" will automatically be an instance of Place, Restaurant, or Bar
The database query performed will have an extra join for each subclass; if you
want to reduce the number of joins and you only need particular subclasses to
be returned as their actual type, you can pass subclass names to
select_subclasses(), much like the built-in
nearby_places = Place.objects.select_subclasses("restaurant") # restaurants will be Restaurant instances, bars will still be Place instances nearby_places = Place.objects.select_subclasses("restaurant", "bar") # all Places will be converted to Restaurant and Bar instances.
It is also possible to use the subclasses themselves as arguments to
select_subclasses, leaving it to calculate the relationship for you:
nearby_places = Place.objects.select_subclasses(Restaurant) # restaurants will be Restaurant instances, bars will still be Place instances nearby_places = Place.objects.select_subclasses(Restaurant, Bar) # all Places will be converted to Restaurant and Bar instances.
It is even possible to mix and match the two:
nearby_places = Place.objects.select_subclasses(Restaurant, "bar") # all Places will be converted to Restaurant and Bar instances.
InheritanceManager also provides a subclass-fetching alternative to the
place = Place.objects.get_subclass(id=some_id) # "place" will automatically be an instance of Place, Restaurant, or Bar
If you don’t explicitly call
InheritanceManager behaves identically to a normal
it’s safe to use as your default manager for the model.
Many custom model managers do nothing more than return a QuerySet that
is filtered in some way.
QueryManager allows you to express this
pattern with a minimum of boilerplate:
from django.db import models from model_utils.managers import QueryManager class Post(models.Model): ... published = models.BooleanField() pub_date = models.DateField() ... objects = models.Manager() public = QueryManager(published=True).order_by('-pub_date')
The kwargs passed to
QueryManager will be passed as-is to the
QuerySet.filter() method. You can also pass a
Q object to
QueryManager to express more complex conditions. Note that you can
set the ordering of the
QuerySet returned by the
by chaining a call to
.order_by() on the
QueryManager (this is
PassThroughManager was removed in django-model-utils 2.4. Use Django’s built-in QuerySet.as_manager() and/or Manager.from_queryset() utilities instead.
Returns only model instances that have the
is_removed field set
to False. Uses
SoftDeletableQuerySet, which ensures model instances
won’t be removed in bulk, but they will be marked as removed instead.
Each of the above manager classes has a corresponding mixin that can be used to
add functionality to any manager. For example, to create a GeoDjango
GeoManager that includes “pass through” functionality, you can write the
from django.contrib.gis.db import models from django.contrib.gis.db.models.query import GeoQuerySet from model_utils.managers import PassThroughManagerMixin class PassThroughGeoManager(PassThroughManagerMixin, models.GeoManager): pass class LocationQuerySet(GeoQuerySet): def within_boundary(self, geom): return self.filter(point__within=geom) def public(self): return self.filter(public=True) class Location(models.Model): point = models.PointField() public = models.BooleanField(default=True) objects = PassThroughGeoManager.for_queryset_class(LocationQuerySet)() Location.objects.public() Location.objects.within_boundary(geom=geom) Location.objects.within_boundary(geom=geom).public()
Now you have a “pass through manager” that can also take advantage of
GeoDjango’s spatial lookups. You can similarly add additional functionality to
any manager by composing that manager with
(Note that any manager class using
InheritanceManagerMixin must return a
QuerySet class using
InheritanceQuerySetMixin from its
method. This means that if composing
QuerySet class passed to
PassThroughManager.for_queryset_class must inherit