Un Manager es la interfaz a través de la cual se proporcionan operaciones de consulta de base de datos a los modelos de Django. Por lo menos un Manager existe para cada modelo en una aplicación de Django.
La forma en que funcionan las clases Manager está documentada en Haciendo consultas; este documento aborda específicamente las opciones de modelo que personalizan el comportamiento de Manager.
Por defecto, Django agrega un Manager con el nombre objects a cada clase de modelo Django. Sin embargo, si deseas utilizar objects como nombre de campo o si deseas utilizar otro nombre que no sea objects para el Manager, puedes renombrarlo en una base por modelo. Para renombrar el Manager para una clase dada, define un atributo de tipo models.Manager() en esa modelo. Por ejemplo:
from django.db import models
class Person(models.Model):
# ...
people = models.Manager()
Al usar este modelo de ejemplo, Person.objects generará una excepción de AttributeError, pero Person.people.all() proporcionará una lista de todos los objetos Person.
Puedes utilizar un administrador personalizado en un modelo particular extendiendo la clase base Manager y instanciando tu administrador personalizado en tu modelo.
Hay dos razones por las que podrías querer personalizar un Manager: para agregar métodos de Manager adicionales, y/o para modificar el conjunto inicial de consultas que devuelve el Manager.
Agregar métodos de Manager adicionales es la forma preferida de agregar funcionalidad «a nivel de tabla» a tus modelos. (Para funcionalidad «a nivel de fila» – i.e., funciones que actúan sobre una instancia individual de un objeto modelo – utiliza Métodos del modelo, no métodos de Manager personalizados.)
Por ejemplo, este administrador personalizado agrega el método with_counts():
from django.db import models
from django.db.models.functions import Coalesce
class PollManager(models.Manager):
def with_counts(self):
return self.annotate(num_responses=Coalesce(models.Count("response"), 0))
class OpinionPoll(models.Model):
question = models.CharField(max_length=200)
objects = PollManager()
class Response(models.Model):
poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE)
# ...
Con este ejemplo, utilizarías OpinionPoll.objects.with_counts() para obtener un conjunto de consultas de objetos OpinionPoll con la atributo adicional num_responses asociado.
Un método de administrador personalizado puede devolver cualquier cosa que desees. No tiene por qué devolver un conjunto de consultas.
Otra cosa que debes tener en cuenta es que los métodos de un Manager pueden acceder a self.model para obtener la clase del modelo al que están asociados.
El conjunto base de un Manager devuelve todos los objetos en el sistema. Por ejemplo, utilizando este modelo:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
…la sentencia Libro.objects.all() devolverá todos los libros en la base de datos.
Puedes sobreescribir el conjunto base de un Manager sobrescribiendo el método get_queryset() del Manager. get_queryset() debe devolver un objeto QuerySet con las propiedades que requieras.
Por ejemplo, en este modelo se definen dos Manager – uno que devuelve todos los objetos y otro que devuelve solo los libros escritos por Roald Dahl:
# First, define the Manager subclass.
class DahlBookManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(author="Roald Dahl")
# Then hook it into the Book model explicitly.
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
objects = models.Manager() # The default manager.
dahl_objects = DahlBookManager() # The Dahl-specific manager.
Con este modelo de muestra, Libro.objects.all() devolverá todos los libros en la base de datos, pero Libro.dahl_objects.all() solo devolverá los escritos por Roald Dahl.
Dado que get_queryset() devuelve un objeto QuerySet, puedes utilizar filter(), exclude() y todos los otros métodos del conjunto en él. Por lo tanto, estas sentencias son todas legales:
Book.dahl_objects.all()
Book.dahl_objects.filter(title="Matilda")
Book.dahl_objects.count()
Este ejemplo también muestra otra técnica interesante: el uso de múltiples managers en el mismo modelo. Puedes asociar tantos instancias de Manager() como desees a un modelo. Esta es una forma no repetitiva de definir «filtros» comunes para tus modelos.
Por ejemplo:
class AuthorManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(role="A")
class EditorManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(role="E")
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
role = models.CharField(max_length=1, choices={"A": _("Author"), "E": _("Editor")})
people = models.Manager()
authors = AuthorManager()
editors = EditorManager()
Este ejemplo te permite solicitar Persona.authors.all(), Persona.editors.all() y Persona.people.all(), lo que produce resultados predecibles.
Si utilizas objetos de gestión personalizados, ten en cuenta que el primer objeto de gestión que encuentra Django (en el orden en que están definidos en el modelo) tiene un estatus especial. Django interpreta al primer objeto de gestión definido en una clase como el «por defecto» y varias partes de Django (incluyendo dumpdata) utilizarán ese objeto de gestión exclusivamente para ese modelo. Como resultado, es una buena idea ser cuidadoso en la elección del administrador por defecto para evitar situaciones en las que sobreescribir get_queryset() resulte en la imposibilidad de recuperar objetos con los que trabajar.
Puedes especificar un administrador personalizado por defecto utilizando Meta.default_manager_name.
Si estás escribiendo algún código que deba manejar un modelo desconocido, por ejemplo, en una aplicación de terceros que implementa una vista genérica, utiliza este administrador (o _base_manager) en lugar de asumir que el modelo tiene un administrador objects.
Los textos traducidos son:
Por lo tanto, no debes sobreescribir get_queryset() para filtrar cualquier fila. Si lo haces así, Django devolverá resultados incompletos.
QuerySet personalizados desde el administrador¶Mientras que la mayoría de los métodos estándar de QuerySet están accesibles directamente desde el Manager, esto solo es el caso para los métodos extra definidos en un QuerySet personalizado si también implementaslos en el Manager:
class PersonQuerySet(models.QuerySet):
def authors(self):
return self.filter(role="A")
def editors(self):
return self.filter(role="E")
class PersonManager(models.Manager):
def get_queryset(self):
return PersonQuerySet(self.model, using=self._db)
def authors(self):
return self.get_queryset().authors()
def editors(self):
return self.get_queryset().editors()
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
role = models.CharField(max_length=1, choices={"A": _("Author"), "E": _("Editor")})
people = PersonManager()
Este ejemplo te permite llamar tanto a authors() como a editors() directamente desde el administrador Person.people.
QuerySet¶En lugar del enfoque anterior que requiere duplicar métodos tanto en el QuerySet como en el Manager, se puede utilizar QuerySet.as_manager() para crear una instancia de Manager con una copia de los métodos de un QuerySet personalizado:
class Person(models.Model):
...
people = PersonQuerySet.as_manager()
La instancia del administrador creada por QuerySet.as_manager() será virtualmente idéntica al PersonManager del ejemplo anterior.
No todos los métodos de QuerySet tienen sentido en el nivel del administrador; por ejemplo, intencionalmente evitamos copiar el método QuerySet.delete() sobre la clase del administrador Manager.
Los métodos se copian según las siguientes reglas:
Métodos públicos se copian por defecto.
Los métodos privados (que comienzan con un guión bajo) no se copian por defecto.
Los métodos con la atributo queryset_only establecido en False siempre se copian.
Los métodos con el atributo queryset_only establecido en True nunca se copian.
Por ejemplo:
class CustomQuerySet(models.QuerySet):
# Available on both Manager and QuerySet.
def public_method(self):
return
# Available only on QuerySet.
def _private_method(self):
return
# Available only on QuerySet.
def opted_out_public_method(self):
return
opted_out_public_method.queryset_only = True
# Available on both Manager and QuerySet.
def _opted_in_private_method(self):
return
_opted_in_private_method.queryset_only = False
from_queryset()¶Para un uso avanzado, es posible que desee tanto un Manager personalizado como un QuerySet personalizado. Puede hacerlo llamando a Manager.from_queryset() lo cual devuelve una subclase de su base Manager con una copia de los métodos del QuerySet personalizados:
class CustomManager(models.Manager):
def manager_only_method(self):
return
class CustomQuerySet(models.QuerySet):
def manager_and_queryset_method(self):
return
class MyModel(models.Model):
objects = CustomManager.from_queryset(CustomQuerySet)()
También puede almacenar la clase generada en una variable:
MyManager = CustomManager.from_queryset(CustomQuerySet)
class MyModel(models.Model):
objects = MyManager()
Aquí está cómo Django maneja gerentes personalizados y herencia de modelos:
Los gerentes de las clases base siempre se heredan por la clase hija, utilizando el orden normal de resolución de nombres de Python (los nombres en la clase hija sobrescriben a todos los demás; luego vienen los nombres en la primera clase padre y así sucesivamente).
Si no se declaran administradores en un modelo y/o sus padres, Django crea automáticamente el administrador objects.
El administrador por defecto de una clase es o bien el que se ha elegido con Meta.default_manager_name, o el primer administrador declarado en el modelo, o el administrador por defecto del primer modelo padre.
Estas reglas proporcionan la flexibilidad necesaria si deseas instalar una colección de administradores personalizados en un grupo de modelos, a través de una clase base abstracta, pero aún así personalizar el administrador por defecto. Por ejemplo, supongamos que tienes esta clase base:
class AbstractBase(models.Model):
# ...
objects = CustomManager()
class Meta:
abstract = True
Si utilizas directamente esta clase en una clase hija, objects será el administrador por defecto si no declaras ningún administrador en la clase hija:
class ChildA(AbstractBase):
# ...
# This class has CustomManager as the default manager.
pass
Si deseas heredar de AbstractBase, pero proporcionar un administrador por defecto diferente, puedes proporcionar el administrador por defecto en la clase hija:
class ChildB(AbstractBase):
# ...
# An explicit default manager.
default_manager = OtherManager()
Aquí, default_manager es el administrador por defecto. El administrador objects sigue estando disponible, ya que se hereda, pero no se utiliza como administrador por defecto.
Finalmente para este ejemplo, supongamos que deseas agregar administradores adicionales a la clase hija, pero aún así utilizar el por defecto de AbstractBase. No puedes agregar directamente el nuevo administrador en la clase hija, ya que eso sobrescribiría el administrador por defecto y tendrías que incluir explícitamente todos los administradores de la clase base abstracta. La solución es poner los administradores adicionales en otra clase base e introducirla en la jerarquía de herencia después de los valores por defecto:
class ExtraManager(models.Model):
extra_manager = OtherManager()
class Meta:
abstract = True
class ChildC(AbstractBase, ExtraManager):
# ...
# Default manager is CustomManager, but OtherManager is
# also available via the "extra_manager" attribute.
pass
Ten en cuenta que si bien puedes definir un administrador personalizado en el modelo abstracto, no puedes invocar ningún método utilizando el modelo abstracto. Es decir:
ClassA.objects.do_something()
es legal, pero:
AbstractBase.objects.do_something()
levantará una excepción. Esto se debe a que los administradores están destinados a encapsular la lógica para gestionar colecciones de objetos. Dado que no puedes tener una colección de objetos abstractos, no tiene sentido gestionarlos. Si tienes funcionalidad que aplica al modelo abstracto, deberías poner esa funcionalidad en un staticmethod o classmethod en el modelo abstracto.
Independientemente de las características que agregues a tu Manager personalizado, debe ser posible hacer una copia superficial de una instancia de Manager; es decir, el siguiente código debe funcionar:
>>> import copy
>>> manager = MyManager()
>>> my_copy = copy.copy(manager)
Django hace copias superficiales de objetos manager durante ciertas consultas; si tu Manager no puede ser copiado, esas consultas fallarán.
Esto no será un problema para la mayoría de los managers personalizados. Si solo estás agregando métodos simples a tu Manager, es poco probable que inadvertidamente hagas instancias de tu Manager incopiables. Sin embargo, si estás sobreescribiendo __getattr__ o algún otro método privado de tu objeto manager que controla el estado del objeto, debes asegurarte de no afectar la capacidad de tu Manager para ser copiado.
may 31, 2026