Este documento describe los detalles de la API Model. Se basa en el material presentado en las guías model y database query, por lo que probablemente querrás leer y entender esos documentos antes de leer este.
A lo largo de esta referencia utilizaremos los modelos de ejemplo del blog presentados en la guía database query guide.
Para crear una nueva instancia de un modelo, instántialo como cualquier otra clase de Python:
Los argumentos de palabra clave son los nombres de los campos que has definido en tu modelo. Ten en cuenta que instanciar un modelo no toca en absoluto a tu base de datos; para eso necesitas save().
Nota
Puede que te sientas tentado a personalizar el modelo sobreescribiendo el método __init__. Si lo haces, ten cuidado de no cambiar la firma del llamado ya que cualquier cambio puede impedir que la instancia del modelo se guarde. Además, referirse a campos del modelo dentro de __init__ puede dar lugar a errores de recurrencia infinita en ciertas circunstancias. En su lugar, intenta utilizar uno de estos enfoques:
Añade un método clase al modelo:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
@classmethod
def create(cls, title):
book = cls(title=title)
# do something with the book
return book
book = Book.create("Pride and Prejudice")
Añade un método a un administrador personalizado (usualmente preferido):
class BookManager(models.Manager):
def create_book(self, title):
book = self.create(title=title)
# do something with the book
return book
class Book(models.Model):
title = models.CharField(max_length=100)
objects = BookManager()
book = Book.objects.create_book("Pride and Prejudice")
El método from_db() se puede utilizar para personalizar la creación de instancias de modelos cuando se cargan desde la base de datos.
El db argumento contiene el alias de la base de datos desde la que se carga el modelo, field_names contiene los nombres de todos los campos cargados y values contiene los valores cargados para cada campo en field_names. Los field_names están en el mismo orden que los values. Si todos los campos del modelo están presentes, entonces values están garantizados a estar en el orden que espera __init__(). Es decir, la instancia se puede crear con cls(*values). Si alguno de los campos está diferido, no aparecerán en field_names. En ese caso, asigna un valor de django.db.models.DEFERRED a cada uno de los campos faltantes.
Además de crear el nuevo modelo, el método from_db() debe establecer las banderas adding y db en la atributo _state del nuevo instante.
A continuación se muestra un ejemplo que muestra cómo grabar los valores iniciales de campos que se cargan desde la base de datos:
from django.db.models import DEFERRED
@classmethod
def from_db(cls, db, field_names, values):
# Default implementation of from_db() (subject to change and could
# be replaced with super()).
if len(values) != len(cls._meta.concrete_fields):
values = list(values)
values.reverse()
values = [
values.pop() if f.attname in field_names else DEFERRED
for f in cls._meta.concrete_fields
]
instance = cls(*values)
instance._state.adding = False
instance._state.db = db
# customization to store the original field values on the instance
instance._loaded_values = dict(
zip(field_names, (value for value in values if value is not DEFERRED))
)
return instance
def save(self, **kwargs):
# Check how the current values differ from ._loaded_values. For example,
# prevent changing the creator_id of the model. (This example doesn't
# support cases where 'creator_id' is deferred).
if not self._state.adding and (
self.creator_id != self._loaded_values["creator_id"]
):
raise ValueError("Updating the value of creator isn't allowed")
super().save(**kwargs)
El ejemplo anterior muestra una implementación completa de from_db() para aclarar cómo hacerlo. En este caso sería posible utilizar un llamado a super() en el método from_db().
Si eliminas un campo de una instancia del modelo, acceder a él nuevamente recarga el valor desde la base de datos:
>>> obj = MyModel.objects.first()
>>> del obj.field
>>> obj.field # Loads the field from the database
Versión asíncrona: arefresh_from_db()
Si necesitas recargar los valores del modelo desde la base de datos, puedes utilizar el método refresh_from_db(). Cuando se llama a este método sin argumentos, se hace lo siguiente:
Se actualizan todos los campos no diferidos del modelo a los valores que están presentes actualmente en la base de datos.
Se eliminan las relaciones cacheadas desde el instante recargado.
Sólo los campos del modelo se recargan desde la base de datos. Otros valores dependientes de la base de datos, como las anotaciones, no se recargan. Tampoco se limpian los atributos @cached_property.
El recarga sucede desde la base de datos en la que se cargó el objeto o desde la base de datos predeterminada si el objeto no se cargó desde la base de datos. Se puede utilizar el argumento using para forzar la base de datos utilizada para el recarga.
Es posible forzar el conjunto de campos a cargar utilizando el argumento fields.
Por ejemplo, para probar que una llamada a update() resultó en la actualización esperada, podrías escribir un test similar a este:
def test_update_result(self):
obj = MyModel.objects.create(val=1)
MyModel.objects.filter(pk=obj.pk).update(val=F("val") + 1)
# At this point obj.val is still 1, but the value in the database
# was updated to 2. The object's updated value needs to be reloaded
# from the database.
obj.refresh_from_db()
self.assertEqual(obj.val, 2)
Ten en cuenta que cuando se accede a campos diferidos, el recarga del valor del campo diferido sucede mediante esta función. Por lo tanto es posible personalizar cómo ocurre el recarga de los campos diferidos. El ejemplo a continuación muestra cómo se puede recargar todos los campos del objeto cuando un campo diferido se recarga:
class ExampleModel(models.Model):
def refresh_from_db(self, using=None, fields=None, **kwargs):
# fields contains the name of the deferred field to be
# loaded.
if fields is not None:
fields = set(fields)
deferred_fields = self.get_deferred_fields()
# If any deferred field is going to be loaded
if fields.intersection(deferred_fields):
# then load all of them
fields = fields.union(deferred_fields)
super().refresh_from_db(using, fields, **kwargs)
El argumento from_queryset permite utilizar una diferente consulta que la creada desde _base_manager. Esto le da más control sobre cómo se recarga el modelo. Por ejemplo, si tu modelo utiliza eliminación suave puedes hacer que refresh_from_db() tenga en cuenta esto:
obj.refresh_from_db(from_queryset=MyModel.active_objects.all())
Puedes cachear objetos relacionados que de otra manera se eliminarían del objeto recargado:
obj.refresh_from_db(from_queryset=MyModel.objects.select_related("related_field"))
Puedes bloquear la fila hasta el final de la transacción antes de recargar los valores del modelo:
obj.refresh_from_db(from_queryset=MyModel.objects.select_for_update())
El argumento from_queryset fue agregado.
Una función auxiliar que devuelve un conjunto conteniendo los nombres de atributo de todos aquellos campos que están actualmente diferidos para este modelo.
Hay cuatro pasos involucrados en la validación de un modelo:
Valida los campos del modelo - Model.clean_fields()
Valida el modelo como un todo - Model.clean()
Valida la unicidad de los campos - Model.validate_unique()
Valida las restricciones - Model.validate_constraints()
Se realizan todos y cada uno de estos pasos cuando se llama al método full_clean() de un modelo.
Cuando se utiliza una instancia de ModelForm, la llamada a is_valid() realizará estos pasos de validación para todos los campos que estén incluidos en el formulario. Consulte la documentación del ModelForm para obtener más información. Deberías llamar al método full_clean() de un modelo solo si planeas manejar errores de validación tú mismo, o si has excluido campos del ModelForm que requieren validación.
Este método llama a Model.clean_fields(), Model.clean(), Model.validate_unique() (si validate_unique es True), y Model.validate_constraints() (si validate_constraints es True) en ese orden, y levanta una ValidationError que tiene un atributo message_dict con errores de todos los cuatro estadios.
El argumento opcional exclude se puede utilizar para proporcionar un conjunto de nombres de campos que pueden ser excluidos de la validación y limpieza. ModelForm utiliza este argumento para excluir campos que no están presentes en tu formulario de ser validados, ya que cualquier error levantado podría no poder corregirse por el usuario.
Ten en cuenta que full_clean() no se llamará automáticamente cuando invoques el método de tu modelo save(). Tendrás que llamarlo manualmente cuando desees ejecutar la validación del modelo en una sola paso para tus modelos creados manualmente. Por ejemplo:
from django.core.exceptions import ValidationError
try:
article.full_clean()
except ValidationError as e:
# Do something based on the errors contained in e.message_dict.
# Display them to a user, or handle them programmatically.
pass
El primer paso full_clean() realiza es limpiar cada campo individual.
Este método validará todos los campos de tu modelo. El argumento opcional exclude te permite proporcionar un conjunto de nombres de campo para excluir de la validación. Si alguno de los campos falla en la validación, levantará una ValidationError.
El segundo paso full_clean() realiza es llamar a la método Model.clean(). Este método debe ser sobrescrito para realizar una validación personalizada en tu modelo.
Este método se debe utilizar para proporcionar validación personalizada de modelos y modificar atributos en tu modelo si es necesario. Por ejemplo, podrías usarlo para proporcionar automáticamente un valor para un campo o realizar una validación que requiera acceso a más de un campo:
import datetime
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _
class Article(models.Model):
...
def clean(self):
# Don't allow draft entries to have a pub_date.
if self.status == "draft" and self.pub_date is not None:
raise ValidationError(_("Draft entries may not have a publication date."))
# Set the pub_date for published items if it hasn't been set already.
if self.status == "published" and self.pub_date is None:
self.pub_date = datetime.date.today()
Nota, sin embargo, que al igual que la función Model.full_clean(), el método clean() de un modelo no se invoca cuando llames a la función save() de tu modelo.
En el ejemplo anterior, la excepción ValidationError lanzada por Model.clean() se instanció con una cadena de texto, por lo que se almacenará en una clave especial del diccionario de errores, NON_FIELD_ERRORS. Esta clave se utiliza para errores relacionados con el modelo completo en lugar de un campo específico:
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
try:
article.full_clean()
except ValidationError as e:
non_field_errors = e.message_dict[NON_FIELD_ERRORS]
Asignar excepciones a un campo específico implica instanciar la ValidationError con un diccionario, donde las claves son los nombres de los campos. Podríamos actualizar el ejemplo anterior para asignar el error al campo pub_date.
class Article(models.Model):
...
def clean(self):
# Don't allow draft entries to have a pub_date.
if self.status == "draft" and self.pub_date is not None:
raise ValidationError(
{"pub_date": _("Draft entries may not have a publication date.")}
)
...
Si detectas errores en múltiples campos durante Model.clean(), también puedes pasar un diccionario que mapee nombres de campos con errores:
raise ValidationError(
{
"title": ValidationError(_("Missing title."), code="required"),
"pub_date": ValidationError(_("Invalid date."), code="invalid"),
}
)
Luego, full_clean() verificará las restricciones únicas en tu modelo.
Cómo levantar errores de validación específicos de campo si esos campos no aparecen en un ModelForm
No puedes levantar errores de validación en Model.clean() para campos que no aparezcan en un formulario de modelo (un formulario puede limitar sus campos utilizando Meta.fields o Meta.exclude). Hacerlo así levantará una ValueError porque el error de validación no podrá asociarse con el campo excluido.
Para resolver este dilema, en su lugar sobreescriba Model.clean_fields() ya que recibe la lista de campos que se excluiron de la validación. Por ejemplo:
class Article(models.Model):
...
def clean_fields(self, exclude=None):
super().clean_fields(exclude=exclude)
if self.status == "draft" and self.pub_date is not None:
if exclude and "status" in exclude:
raise ValidationError(
_("Draft entries may not have a publication date.")
)
else:
raise ValidationError(
{
"status": _(
"Set status to draft if there is not a publication date."
),
}
)
Este método es similar a clean_fields(), pero valida las restricciones de unicidad definidas mediante Field.unique, Field.unique_for_date, Field.unique_for_month, Field.unique_for_year o Meta.unique_together en tu modelo en lugar de los valores individuales de campo. El argumento opcional exclude permite proporcionar un conjunto de nombres de campos para excluir de la validación. Levantará una ValidationError si alguno de los campos falla la validación.
Las restricciones únicas definidas en el Meta.constraints se validan por Model.validate_constraints().
Ten en cuenta que si proporcionas un argumento exclude a validate_unique(), cualquier restricción de unicidad involucrando uno de los campos que proporcionaste no se verificará.
Finalmente, full_clean() verificará otras restricciones en tu modelo.
Este método valida todas las restricciones definidas en Meta.constraints. El argumento opcional exclude permite proporcionar un conjunto de nombres de campos para excluir de la validación. Levantará una ValidationError si alguna restricción falla la validación.
Para guardar un objeto nuevamente en la base de datos, llama a save():
Versión asíncrona: asave()
Para detalles sobre el uso de los argumentos force_insert y force_update, consulte la sección Forzando un INSERT o UPDATE. Para obtener más información sobre el argumento update_fields, consulte la sección Especificar los campos a guardar.
Si deseas un comportamiento de guardado personalizado, puedes sobrescribir este método save(). Consulte la sección Sobreescribiendo métodos predefinidos del modelo para obtener más detalles.
El proceso de guarda del modelo también tiene algunas sutilezas; consulte las secciones a continuación.
Obsoleto desde la versión 5.1: La compatibilidad con argumentos posicionales está desaconsejada.
Si un modelo tiene una AutoField — una clave primaria autoincrementable —, entonces ese valor autoincrementado se calculará y guardará como atributo en tu objeto la primera vez que llames a save():
>>> b2 = Blog(name="Cheddar Talk", tagline="Thoughts on cheese.")
>>> b2.id # Returns None, because b2 doesn't have an ID yet.
>>> b2.save()
>>> b2.id # Returns the ID of your new object.
No hay forma de saber qué será el valor de un ID antes de llamar a save(), porque ese valor es calculado por tu base de datos, no por Django.
Para conveniencia, cada modelo tiene una AutoField llamada id por defecto a menos que especifiques explícitamente primary_key=True en un campo de tu modelo. Consulta la documentación para AutoField para obtener más detalles.
pk¶Independientemente de si defines un campo de clave primaria tú mismo o deja que Django lo suministre por ti, cada modelo tendrá una propiedad llamada pk. Se comporta como cualquier otro atributo en el modelo, pero es en realidad un alias para el campo o campos que componen la clave primaria del modelo. Puedes leer y establecer este valor, exactamente como lo harías con cualquier otro atributo, y se actualizarán los campos correctos en el modelo.
Se agregó soporte para que la clave primaria esté compuesta por múltiples campos a través de CompositePrimaryKey.
Si un modelo tiene un AutoField pero deseas definir el ID de un nuevo objeto explícitamente al guardar, define explícitamente antes de guardar en lugar de confiar en la asignación automática del ID:
>>> b3 = Blog(id=3, name="Cheddar Talk", tagline="Thoughts on cheese.")
>>> b3.id # Returns 3.
>>> b3.save()
>>> b3.id # Returns 3.
Si asignas valores de clave primaria auto-assignados manualmente, asegúrate de no utilizar un valor de clave primaria existente ya. Si creas un nuevo objeto con un valor de clave primaria explícito que ya existe en la base de datos, Django supondrá que estás cambiando el registro existente en lugar de crear uno nuevo.
Dado el ejemplo anterior 'Cheddar Talk' del blog, este ejemplo sobreescribiría el registro previo en la base de datos:
b4 = Blog(id=3, name="Not Cheddar", tagline="Anything but cheese.")
b4.save() # Overrides the previous blog with ID=3!
Véase Cómo Django sabe si actualizar o insertar a continuación para saber por qué sucede esto.
Especificar explícitamente valores de clave primaria auto-assignados es útil principalmente para guardar objetos en lotes, cuando estás seguro de que no habrá colisión de claves primarias.
Si estás utilizando PostgreSQL, la secuencia asociada con la clave primaria puede necesitar actualizarse; véase Especificar manualmente valores de claves primarias autoincrementables.
When you save an object, Django performs the following steps:
Emite un señal pre-guardar. El señal pre_save se envía, permitiendo a cualquier función que esté escuchando esa señal hacer algo.
Preprocesa los datos. Se llama al método pre_save() de cada campo para realizar cualquier modificación automática de los datos que sea necesaria. Por ejemplo, los campos de fecha/hora sobrescriben pre_save() para implementar auto_now_add y auto_now.
Prepara los datos para la base de datos. Se pregunta a cada campo su valor actual en un tipo de dato que pueda ser escrito en la base de datos mediante el método get_db_prep_save().
La mayoría de los campos no requieren preparación de datos. Los tipos de datos simples, como enteros y cadenas, están «listos para escribir» como un objeto Python. Sin embargo, los tipos de datos más complejos a menudo requieren alguna modificación.
Por ejemplo, los campos DateField utilizan un objeto datetime de Python para almacenar datos. Las bases de datos no almacenan objetos datetime, por lo que el valor del campo debe ser convertido en una cadena de fecha ISO-compliant para su inserción en la base de datos.
Inserta los datos en la base de datos. Los datos preprocesados y preparados se componen en una sentencia SQL para su inserción en la base de datos.
Emite un señal post-guardar. La señal post_save se envía, permitiendo a cualquier función que esté escuchando esa señal hacer algo.
Puede haber notado que los objetos de la base de datos de Django utilizan el mismo método save() para crear y cambiar objetos. Django abstracta la necesidad de utilizar sentencias SQL INSERT o UPDATE. Específicamente, cuando llama a save() y el atributo de clave primaria del objeto no define un default o db_default, Django sigue este algoritmo:
Si la propiedad de clave primaria del objeto está configurada en algo excepto None, Django ejecuta un UPDATE.
Si la propiedad de clave primaria del objeto no está configurada o si el UPDATE no actualizó nada (por ejemplo, si la clave primaria está configurada con un valor que no existe en la base de datos), Django ejecuta un INSERT.
Si la propiedad de clave primaria del objeto define una default o db_default, entonces Django ejecuta un UPDATE si es una instancia existente del modelo y la clave primaria está configurada con un valor que existe en la base de datos. De lo contrario, Django ejecuta un INSERT.
La trampa aquí es que debes tener cuidado al no especificar explícitamente un valor de clave primaria cuando se guardan nuevos objetos, si no puedes garantizar que el valor de clave primaria sea inutilizado. Para más información sobre esta sutileza, consulte Explicitly specifying auto-primary-key values arriba y Forcing an INSERT or UPDATE a continuación.
En Django 1.5 y versiones anteriores, Django hacía un SELECT cuando la propiedad de clave primaria estaba configurada. Si el SELECT encontraba una fila, entonces Django hacía un UPDATE, en caso contrario hacía un INSERT. El antiguo algoritmo resulta en una consulta adicional en el caso de UPDATE. Hay algunas circunstancias raras donde la base de datos no informa que se actualizó una fila aunque la base de datos contenga una fila para el valor de clave primaria del objeto. Un ejemplo es el trigger PostgreSQL ON UPDATE que devuelve NULL. En tales casos es posible reversionar al antiguo algoritmo estableciendo la opción select_on_save a True.
En algunas circunstancias raras, es necesario poder forzar el método save() para realizar una consulta SQL INSERT y no recurrir al caso de UPDATE. O viceversa: actualizar si es posible, pero no insertar una nueva fila. En estos casos puedes pasar los parámetros force_insert=True o force_update=True al método save(). Pasar ambos parámetros es un error: no se puede insertar y actualizar al mismo tiempo!
Cuando se utiliza la herencia de tablas múltiples <multi-table-inheritance>, también es posible proporcionar una tupla de clases padre a force_insert para forzar las consultas INSERT para cada base. Por ejemplo:
Restaurant(pk=1, name="Bob's Cafe").save(force_insert=(Place,))
Restaurant(pk=1, name="Bob's Cafe", rating=4).save(force_insert=(Place, Rating))
Puedes pasar force_insert=(models.Model,) para forzar la consulta INSERT para todas las bases. De forma predeterminada, force_insert=True solo fuerza la inserción de una nueva fila para el modelo actual.
Debería ser muy raro que necesites utilizar estos parámetros. Django casi siempre hace lo correcto y tratar de sobreescribir eso llevará a errores difíciles de localizar. Esta característica es solo para uso avanzado.
Usando update_fields se forzará una actualización de manera similar a force_update.
A veces necesitarás realizar una tarea aritmética simple en un campo, como incrementar o decrementar el valor actual. Una forma de lograr esto es hacer la operación aritmética en Python como:
>>> product = Product.objects.get(name="Venezuelan Beaver Cheese")
>>> product.number_sold += 1
>>> product.save()
Si el valor antiguo number_sold recuperado desde la base de datos era 10, entonces se escribirá el valor 11 nuevamente en la base de datos.
El proceso puede hacerse más robusto, evitando una condición de carrera, así como ligeramente más rápido expresando la actualización relativa al valor del campo original, en lugar de como una asignación explícita de un nuevo valor. Django proporciona expresiones F para realizar esta clase de actualizaciones relativas. Utilizando expresiones F, el ejemplo anterior se expresa como:
>>> from django.db.models import F
>>> product = Product.objects.get(name="Venezuelan Beaver Cheese")
>>> product.number_sold = F("number_sold") + 1
>>> product.save()
Para obtener más detalles, consulte la documentación sobre expresiones F y su uso en consultas de actualización.
Si save() se le pasa una lista de nombres de campo como argumento de palabra clave update_fields, solo se actualizarán los campos nombrados en esa lista. Esto puede ser deseable si quieres actualizar solo uno o unos pocos campos en un objeto. Habrá un beneficio ligeramente mayor en rendimiento al evitar que todos los campos del modelo se actualicen en la base de datos. Por ejemplo:
product.name = "Name changed again"
product.save(update_fields=["name"])
El argumento update_fields puede ser cualquier iterable conteniendo cadenas. Un iterable vacío update_fields saltará la actualización. Un valor de None realizará una actualización en todos los campos.
Especificar update_fields forzará una actualización.
When guardando un modelo obtenido mediante la carga diferida de modelos (only() o defer()) solo se actualizarán los campos cargados desde la BD. De hecho, en este caso hay una actualización automática update_fields. Si asignas o cambias el valor de algún campo diferido, el campo se agregará a los campos actualizados.
Field.pre_save() y update_fields
Si se pasa update_fields, solo se llamarán los métodos pre_save() de los campos en update_fields. Por ejemplo, esto significa que los campos de fecha/hora con auto_now=True no se actualizarán a menos que estén incluidos en update_fields.
Versión asíncrona: adelete()
Emite una sentencia SQL DELETE para el objeto. Solo se elimina el objeto en la base de datos; la instancia de Python seguirá existiendo y tendrá datos en sus campos, excepto por la clave primaria establecida en None. Este método devuelve el número de objetos eliminados y un diccionario con el número de eliminaciones por tipo de objeto.
Para obtener más detalles, incluyendo cómo eliminar objetos en lotes, consulte Eliminando objetos.
Si deseas personalizar el comportamiento de la eliminación, puedes sobreescribir el método delete(). Consulta Sobreescribiendo métodos predefinidos del modelo para obtener más detalles.
A veces con la herencia múltiple de tablas (multi-table-inheritance) puede que desees eliminar solo los datos del modelo hijo. Especificando keep_parents=True se mantendrán los datos del modelo padre.
When tú pickle un modelo, su estado actual se pica. Cuando lo desempacotas, contendrá la instancia del modelo en el momento en que se pica, más que los datos que están actualmente en la base de datos.
Un par de métodos de objeto tienen fines especiales.
El método __str__()` se llama cada vez que llamas a str() en un objeto. Django utiliza str(obj) en una serie de lugares. Notablemente, para mostrar un objeto en el sitio administrativo de Django y como valor insertado en un template cuando muestra un objeto. Por lo tanto, siempre debes devolver una representación humana legible del modelo desde el método __str__().
Por ejemplo:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __str__(self):
return f"{self.first_name} {self.last_name}"
El método de igualdad está definido de tal manera que las instancias con el mismo valor de clave primaria y la misma clase concreta se consideran iguales, excepto que las instancias con un valor de clave primaria de None no son iguales a nada excepto a sí mismas. Para modelos proxy, la clase concreta está definida como la primera clase no-proxy padre del modelo; para todos los demás modelos es simplemente la clase del modelo.
Por ejemplo:
from django.db import models
class MyModel(models.Model):
id = models.AutoField(primary_key=True)
class MyProxyModel(MyModel):
class Meta:
proxy = True
class MultitableInherited(MyModel):
pass
# Primary keys compared
MyModel(id=1) == MyModel(id=1)
MyModel(id=1) != MyModel(id=2)
# Primary keys are None
MyModel(id=None) != MyModel(id=None)
# Same instance
instance = MyModel(id=None)
instance == instance
# Proxy model
MyModel(id=1) == MyProxyModel(id=1)
# Multi-table inheritance
MyModel(id=1) != MultitableInherited(id=1)
__hash__()¶La método __hash__() se basa en el valor de la clave primaria de la instancia. Es efectivamente hash(obj.pk). Si la instancia no tiene un valor de clave primaria, se levantará una TypeError (de lo contrario, el método __hash__() devolvería valores diferentes antes y después de que la instancia sea guardada, pero cambiar el valor de __hash__() de una instancia está prohibido en Python.
get_absolute_url()¶Define un método get_absolute_url() para decirle a Django cómo calcular la URL canónica para un objeto. Para los llamadores, este método debería parecer devolver una cadena que se puede utilizar para referirse al objeto sobre HTTP.
Por ejemplo:
def get_absolute_url(self):
return "/people/%i/" % self.id
Si bien este código es correcto y simple, puede no ser la forma más portátil de escribir este tipo de métodos. La función reverse() suele ser la mejor aproximación.
Por ejemplo:
def get_absolute_url(self):
from django.urls import reverse
return reverse("people-detail", kwargs={"pk": self.pk})
Un lugar en el que Django utiliza get_absolute_url() es en la aplicación administrativa. Si un objeto define este método, la página de edición del objeto tendrá un enlace «Ver en sitio» que te llevará directamente a la vista pública del objeto, tal como se da por get_absolute_url().
De manera similar, una pareja de otros bits de Django, como el framework de feed de syndication, utilizan get_absolute_url() cuando está definido. Si tiene sentido que las instancias de su modelo tengan cada una una URL única, debería definir get_absolute_url().
Advertencia
Deberías evitar construir la URL a partir de entrada del usuario no validada, con el fin de reducir posibilidades de envenenamiento de enlaces o redirecciones:
def get_absolute_url(self):
return "/%s/" % self.name
Si self.name es '/example.com' esto devuelve '//example.com/' que, a su vez, es una URL relativa al esquema válida pero no la esperada '/%2Fexample.com/'.
Es buena práctica utilizar get_absolute_url() en plantillas en lugar de codificar las URLs de tus objetos. Por ejemplo, este código de plantilla es malo:
<!-- BAD template code. Avoid! -->
<a href="/people/{{ object.id }}/">{{ object.name }}</a>
Este código de plantilla es mucho mejor:
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
La lógica aquí es que si cambias la estructura del URL de tus objetos, incluso para algo pequeño como corregir un error ortográfico, no quieres tener que buscar en todas partes dónde el URL podría estar creado. Especifica una sola vez en get_absolute_url() y haz que todo tu otro código llame a ese lugar.
Nota
La cadena que devuelves desde get_absolute_url() debe contener solo caracteres ASCII (requerido por la especificación de URI, RFC 3986 Section 2) y estar codificada en URL, si es necesario.
El código y las plantillas que llaman a get_absolute_url() deben poder utilizar el resultado directamente sin ningún procesamiento adicional. Puede desear usar la función django.utils.encoding.iri_to_uri() para ayudar con esto si está utilizando cadenas que contienen caracteres fuera del rango ASCII.
Además de save(), delete(), un objeto de modelo puede tener algunos de los siguientes métodos:
Para cada campo que tenga choices establecido, el objeto tendrá un método get_FOO_display(), donde FOO es el nombre del campo. Este método devuelve el valor «legible por humanos» del campo.
Por ejemplo:
from django.db import models
class Person(models.Model):
SHIRT_SIZES = {
"S": "Small",
"M": "Medium",
"L": "Large",
}
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=2, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'
Para cada DateField y DateTimeField que no tenga null=True, el objeto tendrá métodos get_next_by_FOO() y get_previous_by_FOO(), donde FOO es el nombre del campo. Este devuelve el siguiente y el objeto anterior con respecto al campo de fecha, levantando una DoesNotExist excepción cuando sea apropiado.
Ambos métodos realizarán sus consultas utilizando el administrador predeterminado para el modelo. Si necesita emular la filtración utilizada por un administrador personalizado o quiere realizar una filtración personalizada, ambos métodos también aceptan argumentos de palabra clave opcionales, que deben estar en el formato descrito en Búsquedas de campos.
Ten en cuenta que en el caso de valores de fecha idénticos, estos métodos utilizarán la clave primaria como un desempate. Esto garantiza que no se saltan ni se duplican registros. Eso también significa que no puedes usar esos métodos en objetos sin guardar.
Sobreescribiendo métodos de instancia adicionales
En la mayoría de los casos, sobrescribir o heredar get_FOO_display(), get_next_by_FOO(), y get_previous_by_FOO() debería funcionar como se espera. Dado que son agregados por la metacalse, no es práctico tener en cuenta todas las estructuras de herencia posibles. En casos más complejos debes sobrescribir Field.contribute_to_class() para establecer los métodos que necesitas.
La atributo _state se refiere a un objeto ModelState que sigue el ciclo de vida de la instancia del modelo.
El objeto ModelState tiene dos atributos: adding, una bandera que es True si el modelo aún no ha sido guardado en la base de datos y db, un string que se refiere al alias de la base de datos desde la cual o a la cual se cargó o guardó la instancia.
Nuevas instancias instantaneadas tienen adding=True y db=None, ya que aún no han sido guardadas. Las instancias recuperadas de un QuerySet tendrán adding=False y db establecido en el alias del servidor de base de datos asociado.
El método _is_pk_set() devuelve si el valor de la clave primaria del modelo está establecido. Abstrae la definición de la clave primaria del modelo, garantizando un comportamiento consistente independientemente de la configuración específica de la clave primaria.
may 31, 2026