Una vez que hayas creado tus modelos de datos, Django te da automáticamente una API de abstracción de base de datos que te permite crear, recuperar, actualizar y eliminar objetos. Este documento explica cómo utilizar esta API. Consulta la referencia del modelo de datos para obtener detalles completos de todas las opciones de búsqueda de modelos.
A lo largo de esta guía (y en la referencia), nos referiremos a los siguientes modelos, que comprenden una aplicación de blog:
from datetime import date
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
def __str__(self):
return self.name
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField(default=date.today)
authors = models.ManyToManyField(Author)
number_of_comments = models.IntegerField(default=0)
number_of_pingbacks = models.IntegerField(default=0)
rating = models.IntegerField(default=5)
def __str__(self):
return self.headline
Para representar los datos de la tabla de la base de datos en objetos Python, Django utiliza un sistema intuitivo: una clase de modelo representa una tabla de la base de datos y una instancia de esa clase representa un registro particular en la tabla de la base de datos.
Para crear un objeto, instántialo utilizando argumentos clave para la clase del modelo, luego llama a save() para guardarla en la base de datos.
Suponiendo que los modelos viven en un archivo models.py dentro de una aplicación Django blog, aquí tienes un ejemplo:
>>> from blog.models import Blog
>>> b = Blog(name="Beatles Blog", tagline="All the latest Beatles news.")
>>> b.save()
Esto realiza una sentencia SQL INSERT detrás de escena. Django no accede a la base de datos hasta que explícitamente llames a save().
El método save() no tiene valor de retorno.
Para guardar cambios en un objeto que ya está en la base de datos, utiliza save().
Given un objeto de instancia Blog que ya ha sido guardado en la base de datos, este ejemplo cambia su nombre y actualiza su registro en la base de datos:
>>> b5.name = "New name"
>>> b5.save()
Esta realiza una sentencia SQL UPDATE detrás de escena. Django no accede a la base de datos hasta que explícitamente llames al método save().
ForeignKey y ManyToManyField¶Actualizar un campo de tipo ForeignKey funciona exactamente igual que guardar un campo normal – asigna un objeto del tipo correcto al campo en cuestión. Este ejemplo actualiza el atributo blog de una instancia de Entry entry, suponiendo instancias apropiadas de Entry y Blog ya están guardadas en la base de datos (así que podemos recuperarlas a continuación):
>>> from blog.models import Blog, Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()
Actualizar un campo de tipo ManyToManyField funciona ligeramente diferente – utiliza el método add() sobre el campo para agregar un registro a la relación. Este ejemplo agrega la instancia Author joe al objeto entry:
>>> from blog.models import Author
>>> joe = Author.objects.create(name="Joe")
>>> entry.authors.add(joe)
Para agregar múltiples registros a un campo de tipo ManyToManyField en una sola llamada, incluye múltiples argumentos en la llamada al método add(), como se muestra aquí:
>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john, paul, george, ringo)
Django protestará si intentas asignar o agregar un objeto del tipo incorrecto.
Para recuperar objetos de tu base de datos, construye una QuerySet a través de un Manager en tu clase de modelo.
Una QuerySet representa una colección de objetos de tu base de datos. Puede tener cero, uno o muchos filtros. Los filtros reducen los resultados de la consulta según los parámetros dados. En términos SQL, una QuerySet equivale a una sentencia SELECT, y un filtro es una cláusula limitadora como WHERE o LIMIT.
Obtienes un :class:`~django.db.models.query.QuerySet utilizando el Manager de tu modelo. Cada modelo tiene al menos uno Manager, y se llama objects por defecto. Accede a él directamente mediante la clase del modelo, como se muestra a continuación:
>>> Blog.objects
<django.db.models.manager.Manager object at ...>
>>> b = Blog(name="Foo", tagline="Bar")
>>> b.objects
Traceback:
...
AttributeError: "Manager isn't accessible via Blog instances."
Nota
Un Manager es accesible solo a través de las clases de modelos, en lugar de desde instancias de modelos, para imponer una separación entre «operaciones a nivel de tabla» y «operaciones a nivel de registro».
El Manager es la principal fuente de conjuntos de consultas para un modelo. Por ejemplo, Blog.objects.all() devuelve un :class:`~django.db.models.query.QuerySet que contiene todos los objetos Blog en la base de datos.
La forma más sencilla de recuperar objetos de una tabla es obtener todos ellos. Para hacer esto, utiliza el método all() sobre un Manager:
>>> all_entries = Entry.objects.all()
El método all() devuelve un :class:`~django.db.models.query.QuerySet de todos los objetos en la base de datos.
El :class:`~django.db.models.query.QuerySet devuelto por all() describe a todos los objetos en la tabla de la base de datos. Normalmente, sin embargo, necesitarás seleccionar solo una subconjunto del conjunto completo de objetos.
Para crear tal subconjunto, refinas el inicial :class:`~django.db.models.query.QuerySet, agregando condiciones de filtro. Las dos formas más comunes de refinar un :class:`~django.db.models.query.QuerySet son:
filter(**kwargs)Returns a new QuerySet que contiene objetos que coinciden con los parámetros de búsqueda dados.
exclude(**kwargs)Returns a new QuerySet que contiene objetos que NO coinciden con los parámetros de búsqueda dados.
Los parámetros de búsqueda (**kwargs en las definiciones de función arriba) deben estar en el formato descrito en Búsquedas de campo a continuación.
Por ejemplo, para obtener un QuerySet de entradas de blog del año 2006, utilice la función filter() como se muestra a continuación:
Entry.objects.filter(pub_date__year=2006)
Con la clase por defecto de administrador, es lo mismo que:
Entry.objects.all().filter(pub_date__year=2006)
El resultado de refinar un QuerySet es él mismo un QuerySet, por lo que es posible encadenar refinamientos. Por ejemplo:
>>> Entry.objects.filter(headline__startswith="What").exclude(
... pub_date__gte=datetime.date.today()
... ).filter(pub_date__gte=datetime.date(2005, 1, 30))
Esto toma el inicial QuerySet de todas las entradas en la base de datos, agrega un filtro, luego una exclusión, luego otro filtro. El resultado final es un QuerySet que contiene todas las entradas con un título que comienza con «What», que fueron publicadas entre el 30 de enero de 2005 y la fecha actual.
QuerySet filtrados son únicos¶Cada vez que refinás un conjunto de consultas (QuerySet), obtienes un nuevo conjunto de consultas (QuerySet) que en ningún caso está ligado al conjunto de consultas anterior (QuerySet). Cada refinamiento crea un conjunto de consultas separado y distinto (QuerySet) que se puede almacenar, utilizar y reutilizar.
Ejemplo:
>>> q1 = Entry.objects.filter(headline__startswith="What")
>>> q2 = q1.exclude(pub_date__gte=datetime.date.today())
>>> q3 = q1.filter(pub_date__gte=datetime.date.today())
Estos tres conjuntos de consultas son separados. El primero es una base QuerySet que contiene todas las entradas que contienen un título que comienza con «¿Qué». El segundo es un subconjunto del primero, con criterios adicionales que excluyen registros cuya pub_date es hoy o en el futuro. El tercero es un subconjunto del primero, con criterios adicionales que seleccionan solo los registros cuya pub_date es hoy o en el futuro. La inicial QuerySet (q1) no se ve afectada por el proceso de refinamiento.
QuerySet) son perezosos¶Los objetos QuerySet son perezosos – la creación de un conjunto de consultas (QuerySet) no implica ninguna actividad en la base de datos. Puedes apilar filtros uno encima de otro todo el día, y Django no ejecutará la consulta hasta que el conjunto de consultas (QuerySet) sea evaluado. Mira este ejemplo:
>>> q = Entry.objects.filter(headline__startswith="What")
>>> q = q.filter(pub_date__lte=datetime.date.today())
>>> q = q.exclude(body_text__icontains="food")
>>> print(q)
Aunque esto parece tres accesos a la base de datos, en realidad solo accede a la base de datos una vez, en la última línea (print(q)). En general, los resultados de un conjunto de consultas (QuerySet) no se recuperan de la base de datos hasta que «preguntar» por ellos. Cuando lo haces, el conjunto de consultas (QuerySet) es evaluado accediendo a la base de datos. Para más detalles sobre exactamente cuándo tiene lugar la evaluación, consulta Cuando se evalúan QuerySets.
get()¶filter() siempre te dará un conjunto de consultas (QuerySet), incluso si solo hay un objeto que coincide con la consulta - en este caso, será un conjunto de consultas (QuerySet) que contiene un elemento único.
Si sabes que solo hay un objeto que coincide con tu consulta, puedes utilizar el método get() en un Manager, lo que devuelve el objeto directamente:
>>> one_entry = Entry.objects.get(pk=1)
Puedes usar cualquier expresión de consulta con get(), exactamente como con filter() - nuevamente, consulta Field lookups a continuación.
Los textos traducidos son:
De manera similar, Django protestará si más de un elemento coincide con la consulta get(). En este caso, levantará la excepción MultipleObjectsReturned, que nuevamente es un atributo de la clase del modelo en sí misma.
QuerySet¶La mayoría de las veces utilizarás all(), get(), filter() y exclude() cuando necesites buscar objetos desde la base de datos. Sin embargo, eso es lejos de todo lo que hay; véase el QuerySet API Reference para obtener una lista completa de todos los métodos class:`~django.db.models.query.QuerySet.
QuerySet¶Utiliza un subconjunto del sintaxis de Python para limitar tu QuerySet a un número determinado de resultados. Esto es equivalente a las cláusulas SQL LIMIT y OFFSET.
Por ejemplo, esto devuelve los primeros 5 objetos (LIMIT 5):
>>> Entry.objects.all()[:5]
Esto devuelve los objetos sexto al décimo (OFFSET 5 LIMIT 5):
>>> Entry.objects.all()[5:10]
La indexación negativa (es decir Entry.objects.all()[-1]) no está soportada.
En general, cortar un QuerySet devuelve una nueva QuerySet – no evalúa la consulta. Una excepción es si utilizas el parámetro «step» de la sintaxis de corte de Python. Por ejemplo, esto ejecutaría realmente la consulta para devolver una lista de cada segundo objeto de los primeros 10:
>>> Entry.objects.all()[:10:2]
La traducción de los textos es la siguiente:
Para recuperar un objeto único en lugar de una lista (por ejemplo, SELECT foo FROM bar LIMIT 1), utilice un índice en lugar de una sección. Por ejemplo, esto devuelve el primer Entry en la base de datos, después de ordenar las entradas alfabéticamente por título:
>>> Entry.objects.order_by("headline")[0]
Esto es aproximadamente equivalente a:
>>> Entry.objects.order_by("headline")[0:1].get()
Ten en cuenta que el primero de estos levantará IndexError mientras que el segundo levantará DoesNotExist si no hay objetos que coincidan con los criterios dados. Consulte get() para obtener más detalles.
Las consultas de campos son cómo especificar la carne de una cláusula SQL WHERE. Se especifican como argumentos de palabra clave a los métodos filter(), exclude() y get() de la clase QuerySet.
Las consultas básicas de campos toman la forma field__lookuptype=value. (Eso es un doble guión bajo). Por ejemplo:
>>> Entry.objects.filter(pub_date__lte="2006-01-01")
se traduce (aproximadamente) en el siguiente SQL:
SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';
Cómo esto es posible
Python tiene la capacidad de definir funciones que acepten argumentos de nombre-valor arbitrarios cuyos nombres y valores se evalúan en tiempo de ejecución. Para obtener más información, consulte Keyword Arguments en el tutorial oficial de Python.
El campo especificado en una búsqueda debe ser el nombre de un campo del modelo. Hay una excepción, aunque: en caso de que se trate de ForeignKey, puedes especificar el nombre del campo con sufijo _id. En este caso, el parámetro valor se espera que contenga el valor bruto de la clave primaria del modelo externo. Por ejemplo:
>>> Entry.objects.filter(blog_id=4)
Si pasas un argumento clave inválido, una función de búsqueda levantará TypeError.
La API de bases de datos admite unos dos docenas de tipos de búsqueda; una referencia completa se puede encontrar en la referencia de búsqueda de campos. Para darte una idea de lo que está disponible, aquí tienes algunos de los lookups más comunes que probablemente utilices:
exactUn «match exacto». Por ejemplo:
>>> Entry.objects.get(headline__exact="Cat bites dog")
Generaría SQL del tipo:
SELECT ... WHERE headline = 'Cat bites dog';
Si no proporcionas un tipo de búsqueda (es decir, si tu argumento de palabra clave no contiene un doble guión bajo), se asume que el tipo de búsqueda es exact.
Ejemplo de ello son las siguientes dos declaraciones:
>>> Blog.objects.get(id__exact=14) # Explicit form
>>> Blog.objects.get(id=14) # __exact is implied
Esto es por conveniencia, porque las consultas exact son el caso común.
Un match no sensible a la casilla. Por lo tanto, la consulta:
>>> Blog.objects.get(name__iexact="beatles blog")
Sería un match para una Blog titulada "Beatles Blog", "beatles blog", o incluso "BeAtlES blOG".
contienePrueba de contención sensible a mayúsculas y minúsculas. Por ejemplo:
Entry.objects.get(headline__contains="Lennon")
Se traduce aproximadamente a esta sentencia SQL:
SELECT ... WHERE headline LIKE '%Lennon%';
Nota que esto coincidirá con el titular 'Hoy Lennon honrado' pero no con 'hoy lennon honrado'.
También existe una versión no sensible a mayúsculas y minúsculas, icontains.
endswithBúsqueda de comienzo y fin, respectivamente. También existen versiones no sensibles a mayúsculas y minúsculas llamadas istartswith y iendswith.
De nuevo, esto solo raspa la superficie. Una referencia completa se puede encontrar en el referencia de búsqueda de campos.
Django ofrece una forma poderosa e intuitiva de «seguir» las relaciones en los lookups, tomando cuidado de las SQL JOINs para ti automáticamente, detrás de escena. Para abarcar una relación, utiliza el nombre del campo de campos relacionados a través de modelos, separados por dobles guiones bajos, hasta llegar al campo que deseas.
Este ejemplo recupera todos los objetos Entry con un Blog cuyo name es 'Beatles Blog':
>>> Entry.objects.filter(blog__name="Beatles Blog")
Esta abstracción puede ser tan profunda como desees.
Funciona hacia atrás, también. Si bien puedes personalizarlo, por defecto se refiere a una «relación inversa» en un lookup utilizando el nombre en minúsculas del modelo.
Este ejemplo recupera todos los objetos Blog que tienen al menos un objeto Entry cuyo headline contiene 'Lennon':
>>> Blog.objects.filter(entry__headline__contains="Lennon")
Si estás filtrando a través de múltiples relaciones y uno de los modelos intermedios no tiene un valor que cumpla la condición de filtro, Django tratará como si hubiera una instancia vacía (todos los valores son NULL), pero válida. Esto significa que no se levantará ningún error. Por ejemplo, en este filtro:
Blog.objects.filter(entry__authors__name="Lennon")
(si existiera un modelo relacionado Author), si no había un author asociado con una entrada, se trataría como si también no hubiera un name adjunto, en lugar de levantar un error debido a la falta del author. Normalmente esto es exactamente lo que quieres que suceda. El único caso donde podría ser confuso es si estás utilizando isnull. Así:
Blog.objects.filter(entry__authors__name__isnull=True)
devolverá objetos Blog con un name vacío en el author y también aquellos que tienen un author vacío en la entry. Si no quieres esos últimos objetos, podrías escribir:
Blog.objects.filter(entry__authors__isnull=False, entry__authors__name__isnull=True)
Cuando se atraviesa un ManyToManyField o una relación inversa ForeignKey (como desde Blog hasta Entry), filtrar en múltiples atributos plantea la pregunta de si es necesario que cada atributo coincida con el mismo objeto relacionado. Podríamos buscar blogs que tengan un entry de 2008 con “Lennon” en su titular, o podríamos buscar blogs que simplemente tengan algún entry de 2008 así como alguna entrada más nueva o antigua con “Lennon” en su titular.
Para seleccionar todos los blogs que contienen al menos un entry de 2008 con «Lennon» en su titular (el mismo entry satisface ambas condiciones), escribiríamos:
Blog.objects.filter(entry__headline__contains="Lennon", entry__pub_date__year=2008)
De lo contrario, para realizar una consulta más permisiva que seleccione cualquier blog con alguna entrada con «Lennon» en su titular y alguna entrada de 2008, escribiríamos:
Blog.objects.filter(entry__headline__contains="Lennon").filter(
entry__pub_date__year=2008
)
Supongamos que solo hay un blog que tiene ambas entradas conteniendo «Lennon» y entradas de 2008, pero que ninguna de las entradas de 2008 contenía «Lennon». La primera consulta no devolvería ningún blog, pero la segunda consulta devolvería ese uno. (Esto es porque las entradas seleccionadas por el segundo filtro pueden o no ser las mismas que las entradas en el primer filtro. Estamos filtrando los Blog items con cada declaración de filtro, no los Entry items.) En resumen, si cada condición necesita coincidir con el mismo objeto relacionado, entonces cada una debería estar contenida en un solo filter() llamada.
Nota
Como la segunda (más permisiva) consulta encadena múltiples filtros, realiza múltiples joins a la modelo principal, potencialmente produciendo duplicados.
>>> from datetime import date
>>> beatles = Blog.objects.create(name="Beatles Blog")
>>> pop = Blog.objects.create(name="Pop Music Blog")
>>> Entry.objects.create(
... blog=beatles,
... headline="New Lennon Biography",
... pub_date=date(2008, 6, 1),
... )
<Entry: New Lennon Biography>
>>> Entry.objects.create(
... blog=beatles,
... headline="New Lennon Biography in Paperback",
... pub_date=date(2009, 6, 1),
... )
<Entry: New Lennon Biography in Paperback>
>>> Entry.objects.create(
... blog=pop,
... headline="Best Albums of 2008",
... pub_date=date(2008, 12, 15),
... )
<Entry: Best Albums of 2008>
>>> Entry.objects.create(
... blog=pop,
... headline="Lennon Would Have Loved Hip Hop",
... pub_date=date(2020, 4, 1),
... )
<Entry: Lennon Would Have Loved Hip Hop>
>>> Blog.objects.filter(
... entry__headline__contains="Lennon",
... entry__pub_date__year=2008,
... )
<QuerySet [<Blog: Beatles Blog>]>
>>> Blog.objects.filter(
... entry__headline__contains="Lennon",
... ).filter(
... entry__pub_date__year=2008,
... )
<QuerySet [<Blog: Beatles Blog>, <Blog: Beatles Blog>, <Blog: Pop Music Blog]>
Nota
El comportamiento de filter() para consultas que atraviesan relaciones con valores múltiples, tal como se describe arriba, no está implementado equivalentemente para exclude(). En su lugar, las condiciones en una sola llamada a exclude() no necesariamente se referirán al mismo item.
Por ejemplo, la siguiente consulta excluiría blogs que contengan ambas entradas con «Lennon» en el titular y entradas publicadas en 2008:
Blog.objects.exclude(
entry__headline__contains="Lennon",
entry__pub_date__year=2008,
)
Sin embargo, a diferencia del comportamiento cuando se utiliza filter(), esto no limitará los blogs basados en entradas que satisfagan ambas condiciones. Para hacer eso, es decir, para seleccionar todos los blogs que no contengan entradas publicadas con «Lennon» que fueron publicadas en 2008, necesitarías realizar dos consultas:
Blog.objects.exclude(
entry__in=Entry.objects.filter(
headline__contains="Lennon",
pub_date__year=2008,
),
)
En los ejemplos dados hasta ahora, hemos construido filtros que comparan el valor de un campo del modelo con una constante. Pero ¿qué pasa si quieres comparar el valor de un campo del modelo con otro campo en el mismo modelo?
Django proporciona F expressions para permitir comparaciones de este tipo. Las instancias de F() actúan como una referencia a un campo del modelo dentro de una consulta. Estas referencias se pueden utilizar luego en los filtros de la consulta para comparar los valores de dos campos diferentes en el mismo instancia del modelo.
Por ejemplo, para encontrar una lista de todos los artículos de blog que han tenido más comentarios que pingbacks, construimos un objeto F() para referenciar el recuento de pingbacks y utilizamos ese objeto F() en la consulta:
>>> from django.db.models import F
>>> Entry.objects.filter(number_of_comments__gt=F("number_of_pingbacks"))
Django admite el uso de aritmética con F() objetos, tanto con constantes como con otros objetos F(), incluyendo adición, resta, multiplicación, división, módulo y potencia. Para encontrar todos los artículos de blog con más del doble número de comentarios que pingbacks, modificamos la consulta:
>>> Entry.objects.filter(number_of_comments__gt=F("number_of_pingbacks") * 2)
Para encontrar todos los entradas donde el rating de la entrada es menor que la suma del recuento de pingback y comentario, emitiríamos la siguiente consulta:
>>> Entry.objects.filter(rating__lt=F("number_of_comments") + F("number_of_pingbacks"))
También puedes utilizar la notación con doble guión bajo para cruzar relaciones en un objeto F(). Un objeto F() con un doble guión bajo introducirá cualquier unión necesaria para acceder al objeto relacionado. Por ejemplo, para recuperar todas las entradas donde el nombre del autor es el mismo que el nombre de la blog, podríamos emitir la siguiente consulta:
>>> Entry.objects.filter(authors__name=F("blog__name"))
Para campos de fecha y hora, puedes sumar o restar un objeto timedelta. El siguiente devolvería todas las entradas que fueron modificadas más de 3 días después de su publicación:
>>> from datetime import timedelta
>>> Entry.objects.filter(mod_date__gt=F("pub_date") + timedelta(days=3))
Los objetos F() admiten operaciones bit a bit mediante .bitand(), .bitor(), .bitxor(), .bitrightshift() y .bitleftshift(). Por ejemplo:
>>> F("somefield").bitand(16)
Oracle
Oracle no admite la operación de XOR bit a bit.
Django admite el uso de transformaciones en expresiones.
Por ejemplo, para encontrar todos los objetos Entry publicados en el mismo año que fueron modificados por última vez:
>>> from django.db.models import F
>>> Entry.objects.filter(pub_date__year=F("mod_date__year"))
Para encontrar el primer año en que se publicó una entrada, podemos emitir la consulta:
>>> from django.db.models import Min
>>> Entry.objects.aggregate(first_published_year=Min("pub_date__year"))
Este ejemplo encuentra el valor de la entrada más puntuada y el número total de comentarios en todas las entradas para cada año:
>>> from django.db.models import OuterRef, Subquery, Sum
>>> Entry.objects.values("pub_date__year").annotate(
... top_rating=Subquery(
... Entry.objects.filter(
... pub_date__year=OuterRef("pub_date__year"),
... )
... .order_by("-rating")
... .values("rating")[:1]
... ),
... total_comments=Sum("number_of_comments"),
... )
pk¶Por conveniencia, Django proporciona una búsqueda por pk (clave primaria).
En el ejemplo del modelo Blog, la clave primaria es el campo id, por lo que estas tres declaraciones son equivalentes:
>>> Blog.objects.get(id__exact=14) # Explicit form
>>> Blog.objects.get(id=14) # __exact is implied
>>> Blog.objects.get(pk=14) # pk implies id__exact
El uso de pk no está limitado a consultas __exact – cualquier término de consulta se puede combinar con pk para realizar una consulta en la clave primaria de un modelo:
# Get blogs entries with id 1, 4 and 7
>>> Blog.objects.filter(pk__in=[1, 4, 7])
# Get all blog entries with id > 14
>>> Blog.objects.filter(pk__gt=14)
Las búsquedas por pk también funcionan a través de joins. Por ejemplo, estas tres declaraciones son equivalentes:
>>> Entry.objects.filter(blog__id__exact=3) # Explicit form
>>> Entry.objects.filter(blog__id=3) # __exact is implied
>>> Entry.objects.filter(blog__pk=3) # __pk implies __id__exact
LIKE¶Los textos traducidos son:
Esto significa que las cosas deberían funcionar intuitivamente, para que la abstracción no se filtre. Por ejemplo, para recuperar todas las entradas que contengan un signo de porcentaje, utilice el signo de porcentaje como cualquier otro carácter.
>>> Entry.objects.filter(headline__contains="%")
Django se encarga del citado para usted; la sentencia SQL resultante tendrá algo como esto:
SELECT ... WHERE headline LIKE '%\%%';
Lo mismo ocurre con los guiones bajos. Ambos signos de porcentaje y guiones bajos se manejan de manera transparente.
QuerySet¶Cada QuerySet contiene un caché para minimizar el acceso a la base de datos. Entender cómo funciona permitirá que escribas el código más eficiente.
En una QuerySet recién creada, el caché está vacío. La primera vez que se evalúa una QuerySet – y, por lo tanto, sucede una consulta a la base de datos – Django almacena los resultados de la consulta en el caché de la QuerySet y devuelve los resultados que han sido solicitados explícitamente (por ejemplo, el siguiente elemento, si se está iterando sobre la QuerySet). Las evaluaciones posteriores de la QuerySet reutilizan los resultados almacenados en caché.
Ten en cuenta este comportamiento del caché, porque puede morderte si no utilizas tus QuerySet correctamente. Por ejemplo, lo siguiente creará dos QuerySet, evaluará y descartará:
>>> print([e.headline for e in Entry.objects.all()])
>>> print([e.pub_date for e in Entry.objects.all()])
Eso significa que se ejecutará la misma consulta a la base de datos dos veces, lo que duplica el carga de trabajo en la base de datos. Además, existe la posibilidad de que las dos listas no incluyan los mismos registros de la base de datos, porque un Entry puede haber sido agregado o eliminado en el instante entre las dos solicitudes.
Para evitar este problema, guarde la QuerySet y reutilízala:
>>> queryset = Entry.objects.all()
>>> print([p.headline for p in queryset]) # Evaluate the query set.
>>> print([p.pub_date for p in queryset]) # Reuse the cache from the evaluation.
QuerySets no están cacheados¶Los querysets no siempre almacenan sus resultados en caché. Cuando se evalúa solo una parte del queryset, se verifica la caché, pero si no está poblada entonces los elementos devueltos por la consulta posterior no están cacheados. Específicamente, esto significa que limitar el queryset utilizando un array de slices o un índice no poblará la caché.
Por ejemplo, obtener repetidamente un cierto índice en un objeto de queryset consultará la base de datos cada vez:
>>> queryset = Entry.objects.all()
>>> print(queryset[5]) # Queries the database
>>> print(queryset[5]) # Queries the database again
Sin embargo, si el conjunto completo del queryset ya ha sido evaluado, se verificará la caché en lugar de eso:
>>> queryset = Entry.objects.all()
>>> [entry for entry in queryset] # Queries the database
>>> print(queryset[5]) # Uses cache
>>> print(queryset[5]) # Uses cache
Aquí hay algunos ejemplos de otras acciones que resultarán en la evaluación completa del conjunto y por lo tanto poblará la caché:
>>> [entry for entry in queryset]
>>> bool(queryset)
>>> entry in queryset
>>> list(queryset)
Nota
Simplemente imprimir el queryset no poblará la caché. Esto es porque la llamada a __repr__() solo devuelve una sección del conjunto completo.
Si estás escribiendo vistas o código asíncronos, no puedes utilizar el ORM para consultas de la manera que hemos descrito anteriormente, ya que no puedes llamar a código sincrónico bloqueante desde código asíncrono - bloqueará el bucle de eventos (o, más probablemente, Django notificará y levantará una SynchronousOnlyOperation para evitar eso).
Por suerte, puedes realizar muchas consultas utilizando las APIs de consulta asíncronas de Django. Cada método que podría bloquear - como get() o delete() - tiene una variante asíncrona (aget() o adelete()), y cuando iteres sobre resultados, puedes utilizar la iteración asíncrona (async for) en lugar de eso.
La traducción de los textos es la siguiente:
async for entry in Authors.objects.filter(name__startswith="A"):
...
Ten en cuenta que también no puedes hacer otras cosas que podrían iterar sobre el conjunto de consultas, como envolverlo con list() para forzar su evaluación (puedes usar async for en una comprensión si lo deseas).
Porque los métodos del conjunto de consultas como filter() y exclude() no ejecutan realmente la consulta - establecen el conjunto de consultas para que se ejecute cuando se itera sobre él - puedes usarlos libremente en código asíncrono. Para una guía sobre qué métodos pueden seguir siendo utilizados de esta manera, y cuáles tienen versiones asíncronas, lee la siguiente sección.
Algunos métodos en administradores y conjuntos de consultas - como get() y first() - fuerzan la ejecución del conjunto de consultas y son bloqueantes. Algunos, como filter() y exclude(), no fuerzan la ejecución y por lo tanto son seguros para ejecutar desde código asíncrono. Pero ¿cómo se supone que debes saber la diferencia?
Si bien podrías buscar alrededor y ver si hay una versión con prefijo a del método (por ejemplo, tenemos aget() pero no afilter(), hay un método más lógico - busca en qué tipo de método es en la referencia del conjunto de consultas.
Allí encontrarás los métodos de los conjuntos de consultas agrupados en dos secciones:
Métodos que devuelven nuevos conjuntos de consultas: Estos son los no bloqueantes y no tienen versiones asíncronas. Estás libre para usar estos en cualquier situación, aunque lee las notas sobre defer() y only() antes de usarlos.
Métodos que no devuelven conjuntos de consultas: Estos son los bloqueantes y tienen versiones asíncronas - el nombre asíncrono para cada uno se indica en su documentación, aunque nuestro patrón estándar es agregar un prefijo a.
Usando esta distinción, puedes determinar cuándo necesitas usar versiones asíncronas y cuándo no. Por ejemplo, aquí tienes una consulta asíncrona válida:
user = await User.objects.filter(username=my_input).afirst()
filter() devuelve una consulta de queryset, y por lo tanto es posible seguir concatenándolo dentro de un entorno asíncrono, mientras que first() evalúa y devuelve una instancia del modelo - por lo tanto, cambiamos a afirst(), y usamos await al principio de la expresión completa para llamarla de manera amigable con el entorno asíncrono.
Nota
Si olvidas poner la parte await, es posible que veas errores como «objeto coroutine no tiene atributo x» o «<coroutine …>» cadenas en lugar de tus instancias del modelo. Si alguna vez ves estos, estás faltando un await en algún lugar para convertir ese coroutine en un valor real.
Las transacciones no están actualmente soportadas con consultas y actualizaciones asíncronas. Te encontrarás que intentar usar una levanta SynchronousOnlyOperation.
Si deseas utilizar una transacción, sugerimos escribir tu código ORM dentro de una función sincrónica separada y luego llamar a esa función utilizando sync_to_async - consulta Soporte asíncrono para más información.
JSONField¶La implementación de consultas es diferente en JSONField, principalmente debido a la existencia de transformaciones de clave. Para demostrarlo, usaremos el siguiente modelo:
from django.db import models
class Dog(models.Model):
name = models.CharField(max_length=200)
data = models.JSONField(null=True)
def __str__(self):
return self.name
None¶Como con otros campos, almacenar None como valor del campo almacena SQL NULL. Si bien no se recomienda, es posible almacenar JSON escalar null en lugar de SQL NULL utilizando Value(None, JSONField()).
Independientemente de cuál de los valores se almacene, cuando se recupera desde la base de datos, la representación Python del JSON escalar null es la misma que SQL NULL, es decir, None. Por lo tanto, puede ser difícil distinguir entre ellos.
Este es el texto traducido:
Al realizar consultas, el valor None siempre se interpretará como JSON null. Para consultar SQL NULL, utilice isnull:
>>> Dog.objects.create(name="Max", data=None) # SQL NULL.
<Dog: Max>
>>> Dog.objects.create(name="Archie", data=Value(None, JSONField())) # JSON null.
<Dog: Archie>
>>> Dog.objects.filter(data=None)
<QuerySet [<Dog: Archie>]>
>>> Dog.objects.filter(data=Value(None, JSONField()))
<QuerySet [<Dog: Archie>]>
>>> Dog.objects.filter(data__isnull=True)
<QuerySet [<Dog: Max>]>
>>> Dog.objects.filter(data__isnull=False)
<QuerySet [<Dog: Archie>]>
A menos que estés seguro de querer trabajar con valores SQL NULL, considera establecer null=False y proporcionar un valor por defecto adecuado para los valores vacíos, como default=dict.
Nota
Almacendar JSON escalar null no viola null=False.
Para consultar según una clave de diccionario dada, utilice esa clave como nombre de consulta:
>>> Dog.objects.create(
... name="Rufus",
... data={
... "breed": "labrador",
... "owner": {
... "name": "Bob",
... "other_pets": [
... {
... "name": "Fishy",
... }
... ],
... },
... },
... )
<Dog: Rufus>
>>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": None})
<Dog: Meg>
>>> Dog.objects.filter(data__breed="collie")
<QuerySet [<Dog: Meg>]>
Pueden unirse varias claves para formar una búsqueda por ruta:
>>> Dog.objects.filter(data__owner__name="Bob")
<QuerySet [<Dog: Rufus>]>
Si la clave es un entero, se interpretará como transformación de índice en un array:
>>> Dog.objects.filter(data__owner__other_pets__0__name="Fishy")
<QuerySet [<Dog: Rufus>]>
Si la clave que deseas consultar coincide con el nombre de otra consulta, utilice la contains lookup en su lugar.
Para consultar claves faltantes, utilice la búsqueda isnull:
>>> Dog.objects.create(name="Shep", data={"breed": "collie"})
<Dog: Shep>
>>> Dog.objects.filter(data__owner__isnull=True)
<QuerySet [<Dog: Shep>]>
Nota
Los textos traducidos son:
KT() expressions¶Representa el valor de texto de una transformación de clave, índice o ruta de campo JSON. Puedes utilizar la notación de doble guión bajo en lookup para encadenar transformaciones de claves y índices de diccionario.
Por ejemplo:
>>> from django.db.models.fields.json import KT
>>> Dog.objects.create(
... name="Shep",
... data={
... "owner": {"name": "Bob"},
... "breed": ["collie", "lhasa apso"],
... },
... )
<Dog: Shep>
>>> Dog.objects.annotate(
... first_breed=KT("data__breed__1"), owner_name=KT("data__owner__name")
... ).filter(first_breed__startswith="lhasa", owner_name="Bob")
<QuerySet [<Dog: Shep>]>
Nota
Debido a la forma en que funcionan las consultas de clave-ruta, exclude() y filter() no están garantizados para producir conjuntos exhaustivos. Si deseas incluir objetos que no tienen la ruta, agrega el lookup isnull.
Advertencia
Dado que cualquier cadena podría ser una clave en un objeto JSON, cualquier lookup distinto de los listados a continuación se interpretará como una búsqueda de claves. No se levantarán errores. Ten especial cuidado con los errores de tipado y siempre verifica tus consultas para asegurarte de que funcionan como deseas.
Usuarios de MariaDB y Oracle
Al utilizar order_by() en transformaciones de clave, índice o ruta, se ordenarán los objetos utilizando la representación de cadena de los valores. Esto es porque MariaDB y Oracle Database no proporcionan una función que convierta los valores JSON en sus equivalentes SQL.
Usuarios de Oracle
En Oracle Database, utilizar None como valor de búsqueda en una consulta exclude() devolverá objetos que no tienen null como valor en la ruta dada, incluyendo objetos que no tengan la ruta. En otros backends de bases de datos, la consulta devolverá objetos que tienen la ruta y el valor no es null.
Usuarios de PostgreSQL
En PostgreSQL, si se utiliza solo una clave o índice, se utiliza el operador SQL ->. Si se utilizan múltiples operadores entonces se utiliza el operador #>.
Usuarios de SQLite
En SQLite, los valores de cadena "true", "false", y "null" siempre se interpretarán como True, False, y JSON null respectivamente.
contains¶La búsqueda contains está sobrescrita en JSONField. Los objetos devueltos son aquellos donde las pares de clave-valor dadas se encuentran todos contenidos en el nivel superior del campo. Por ejemplo:
>>> Dog.objects.create(name="Rufus", data={"breed": "labrador", "owner": "Bob"})
<Dog: Rufus>
>>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
<Dog: Meg>
>>> Dog.objects.create(name="Fred", data={})
<Dog: Fred>
>>> Dog.objects.create(
... name="Merry", data={"breed": "pekingese", "tricks": ["fetch", "dance"]}
... )
>>> Dog.objects.filter(data__contains={"owner": "Bob"})
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
>>> Dog.objects.filter(data__contains={"breed": "collie"})
<QuerySet [<Dog: Meg>]>
>>> Dog.objects.filter(data__contains={"tricks": ["dance"]})
<QuerySet [<Dog: Merry>]>
Oracle y SQLite
No se admite contains en Oracle y SQLite.
contained_by¶Esta es la inversa de la búsqueda contiene - los objetos devueltos serán aquellos donde las pares clave-valor del objeto son un subconjunto de los que se pasan en el valor. Por ejemplo:
>>> Dog.objects.create(name="Rufus", data={"breed": "labrador", "owner": "Bob"})
<Dog: Rufus>
>>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
<Dog: Meg>
>>> Dog.objects.create(name="Fred", data={})
<Dog: Fred>
>>> Dog.objects.create(
... name="Merry", data={"breed": "pekingese", "tricks": ["fetch", "dance"]}
... )
>>> Dog.objects.filter(data__contained_by={"breed": "collie", "owner": "Bob"})
<QuerySet [<Dog: Meg>, <Dog: Fred>]>
>>> Dog.objects.filter(data__contained_by={"breed": "collie"})
<QuerySet [<Dog: Fred>]>
>>> Dog.objects.filter(
... data__contained_by={"breed": "pekingese", "tricks": ["dance", "fetch", "hug"]}
... )
<QuerySet [<Dog: Merry>, <Dog: Fred>]>
Oracle y SQLite
contained_by no está soportado en Oracle y SQLite.
Regresa objetos donde la clave dada está en el nivel superior de los datos. Por ejemplo:
>>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
<Dog: Rufus>
>>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
<Dog: Meg>
>>> Dog.objects.filter(data__has_key="owner")
<QuerySet [<Dog: Meg>]>
Retorna objetos donde todos los claves dadas están en el nivel superior de los datos. Por ejemplo:
>>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
<Dog: Rufus>
>>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
<Dog: Meg>
>>> Dog.objects.filter(data__has_keys=["breed", "owner"])
<QuerySet [<Dog: Meg>]>
Regresa objetos donde cualquier de las claves dadas estén en el nivel superior de los datos. Por ejemplo:
>>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
<Dog: Rufus>
>>> Dog.objects.create(name="Meg", data={"owner": "Bob"})
<Dog: Meg>
>>> Dog.objects.filter(data__has_any_keys=["owner", "breed"])
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
Las consultas de argumentos de palabra clave – en filter(), etc. – se «AND»ean entre sí. Si necesitas ejecutar consultas más complejas (por ejemplo, consultas con sentencias OR), puedes utilizar objetos Q.
Un objeto Q object (django.db.models.Q) es un objeto utilizado para encapsular una colección de argumentos de palabra clave. Estos argumentos de palabra clave se especifican como en «Búsquedas de campo» arriba.
Por ejemplo, este objeto Q encapsula una sola consulta LIKE:
from django.db.models import Q
Q(question__startswith="What")
Los objetos Q pueden combinarse utilizando los operadores &, | y ^. Cuando un operador se utiliza en dos objetos Q, produce un nuevo objeto Q.
Por ejemplo, esta sentencia produce un solo objeto Q que representa la «OR» de dos consultas "question__startswith":
Q(question__startswith="Who") | Q(question__startswith="What")
Esto es equivalente a la siguiente cláusula SQL WHERE:
WHERE question LIKE 'Who%' OR question LIKE 'What%'
Puedes componer declaraciones de complejidad arbitraria combinando objetos Q con los operadores &, | y ^ y utilizando agrupación en paréntesis. Además, los objetos Q pueden ser negados utilizando el operador ~, lo que permite consultas combinadas que combinen tanto una consulta normal como una consulta negada (NOT):
Q(question__startswith="Who") | ~Q(pub_date__year=2005)
Cada función de búsqueda que tome argumentos de palabra clave (por ejemplo, filter(), exclude(), get()) también puede recibir uno o más objetos Q como argumentos posicionales (no-nombrados). Si proporcionas múltiples argumentos de objeto Q a una función de búsqueda, los argumentos se «AND»ean entre sí. Por ejemplo:
Poll.objects.get(
Q(question__startswith="Who"),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
)
… se traduce aproximadamente en la siguiente SQL:
SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
Las funciones de búsqueda pueden mezclar el uso de objetos Q y argumentos de palabra clave. Todos los argumentos proporcionados a una función de búsqueda (ya sean argumentos de palabra clave o objetos Q) se «AND»ean entre sí. Sin embargo, si se proporciona un objeto Q, debe preceder la definición de cualquier argumento de palabra clave. Por ejemplo:
Poll.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
question__startswith="Who",
)
… sería una consulta válida, equivalente al ejemplo anterior; pero:
# INVALID QUERY
Poll.objects.get(
question__startswith="Who",
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
)
No serían válidos.
Ver también
Los ejemplos de consultas OR en <tests/or_lookups/tests.py> en las pruebas unitarias de Django muestran algunas posibles utilizaciones de Q.
Para comparar dos instancias de modelo, utiliza el operador de comparación estándar de Python, el signo igual doble: ==. Detrás de escena, eso compara los valores de la clave primaria de dos modelos.
Utilizando el ejemplo de Entry anterior, las siguientes dos declaraciones son equivalentes:
>>> some_entry == other_entry
>>> some_entry.id == other_entry.id
Si la clave primaria de un modelo no se llama id, no hay problema. Las comparaciones siempre utilizarán la clave primaria, sea cual sea su nombre. Por ejemplo, si el campo de la clave primaria de un modelo se llama name, estas dos declaraciones son equivalentes:
>>> some_obj == other_obj
>>> some_obj.name == other_obj.name
El método delete, convenientemente, se llama delete(). Este método elimina inmediatamente el objeto y devuelve el número de objetos eliminados y un diccionario con el número de eliminaciones por tipo de objeto. Ejemplo:
>>> e.delete()
(1, {'blog.Entry': 1})
También puedes eliminar objetos en masa. Cada conjunto de consultas QuerySet tiene un método delete(), que elimina a todos los miembros de ese conjunto de consultas.
Por ejemplo, esto elimina todos los objetos Entry con un año de pub_date de 2005:
>>> Entry.objects.filter(pub_date__year=2005).delete()
(5, {'webapp.Entry': 5})
Tenga en cuenta que esto se ejecutará puramente en SQL siempre que sea posible, y por lo tanto los métodos delete() de instancias individuales de objetos no necesariamente serán llamados durante el proceso. Si ha proporcionado un método personalizado delete() en una clase de modelo y quiere asegurarse de que se llama, deberá «manualmente» eliminar instancias de ese modelo (por ejemplo, iterando sobre un conjunto de consultas QuerySet y llamando a delete() en cada objeto individualmente) en lugar de utilizar el método bulk delete() de un conjunto de consultas QuerySet.
Cuando Django elimina un objeto, por defecto emula el comportamiento de la restricción SQL ON DELETE CASCADE – en otras palabras, cualquier objeto que tenga claves foráneas apuntando al objeto a eliminar se eliminarán junto con él. Por ejemplo:
b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()
Este comportamiento de cascada es personalizable mediante el argumento on_delete a la clase ForeignKey.
Ten en cuenta que delete() es el único método de un conjunto de consultas QuerySet que no está expuesto en un administrador Manager en sí mismo. Esto es una medida de seguridad para evitar que accidentalmente solicites Entry.objects.delete(), y elimines todos los registros. Si quieres eliminar todos los objetos, entonces tienes que solicitar explícitamente un conjunto de consultas completo:
Entry.objects.all().delete()
Aunque no hay un método integrado para copiar instancias de modelos, es posible crear fácilmente una nueva instancia con todos los valores de campos copiados. En el caso más simple, puedes establecer pk en None y _state.adding a True. Utilizando nuestro ejemplo de blog:
blog = Blog(name="My blog", tagline="Blogging is easy")
blog.save() # blog.pk == 1
blog.pk = None
blog._state.adding = True
blog.save() # blog.pk == 2
Las cosas se complican si utilizas herencia. Considera una subclase de Blog:
class ThemeBlog(Blog):
theme = models.CharField(max_length=200)
django_blog = ThemeBlog(name="Django", tagline="Django is easy", theme="python")
django_blog.save() # django_blog.pk == 3
Debido a cómo funciona la herencia, debes establecer tanto pk como id en None, y _state.adding a True
django_blog.pk = None
django_blog.id = None
django_blog._state.adding = True
django_blog.save() # django_blog.pk == 4
Este proceso no copia las relaciones que no forman parte de la tabla del modelo en la base de datos. Por ejemplo, Entry tiene un campo ManyToManyField con Author. Después de duplicar una entrada, debes establecer las relaciones muchos-a-muchos para la nueva entrada:
entry = Entry.objects.all()[0] # some previous entry
old_authors = entry.authors.all()
entry.pk = None
entry._state.adding = True
entry.save()
entry.authors.set(old_authors)
Para un campo OneToOneField, debes duplicar el objeto relacionado y asignarlo al campo del nuevo objeto para evitar violar la restricción única uno-a-uno. Por ejemplo, suponiendo que entry ya está duplicada como se indica arriba:
detail = EntryDetail.objects.all()[0]
detail.pk = None
detail._state.adding = True
detail.entry = entry
detail.save()
A veces quieres establecer un campo a un valor particular para todos los objetos en un conjunto de consultas QuerySet. Puedes hacer esto con el método update(). Por ejemplo:
# Update all the headlines with pub_date in 2007.
Entry.objects.filter(pub_date__year=2007).update(headline="Everything is the same")
Solo puedes establecer campos no relacionados y campos ForeignKey utilizando este método. Para actualizar un campo no relacionado, proporciona el nuevo valor como una constante. Para actualizar campos ForeignKey, establece el nuevo valor en ser la nueva instancia del modelo al que quieres apuntar. Por ejemplo:
>>> b = Blog.objects.get(pk=1)
# Change every Entry so that it belongs to this Blog.
>>> Entry.objects.update(blog=b)
El método update() se aplica de inmediato y devuelve el número de filas coincidentes con la consulta (que puede no ser igual al número de filas actualizadas si algunas filas ya tienen el nuevo valor). La única restricción en el conjunto de consultas QuerySet que se está actualizando es que solo puede acceder a una tabla de base de datos: la tabla principal del modelo. Puedes filtrar basado en campos relacionados, pero solo puedes actualizar columnas en la tabla principal del modelo. Ejemplo:
>>> b = Blog.objects.get(pk=1)
# Update all the headlines belonging to this Blog.
>>> Entry.objects.filter(blog=b).update(headline="Everything is the same")
Ten en cuenta que el método update() se convierte directamente en una sentencia SQL. Es una operación de actualización en masa para actualizaciones directas. No ejecuta los métodos save() en tus modelos, ni emite los señales pre_save o post_save (que son consecuencia del llamado a save()), ni honra la opción de campo auto_now. Si quieres guardar cada item en un conjunto de consultas QuerySet y asegurarte de que el método save() se llama en cada instancia, no necesitas ninguna función especial para manejar eso. Recorrelos y llama a save():
for item in my_queryset:
item.save()
Las llamadas a la actualización también pueden utilizar expresiones F para actualizar un campo basado en el valor de otro campo del modelo. Esto es especialmente útil para incrementar contadores basados en su valor actual. Por ejemplo, para incrementar el recuento de pingback para cada entrada en el blog:
>>> Entry.objects.update(number_of_pingbacks=F("number_of_pingbacks") + 1)
Sin embargo, a diferencia de los objetos F() en cláusulas de filtro y exclusión, no puedes introducir joins cuando utilizas objetos F() en una actualización – solo puedes referenciar campos locales al modelo que se está actualizando. Si intentas introducir un join con un objeto F(), se levantará un error FieldError:
# This will raise a FieldError
>>> Entry.objects.update(headline=F("blog__name"))
Si te encuentras necesitado de escribir una consulta SQL que es demasiado compleja para que el mapeador de base de datos de Django la maneje, puedes recurrir a escribirla por mano. Django tiene un par de opciones para escribir consultas SQL crudas; véase Ejecutando consultas SQL crudas.
Finalmente, es importante tener en cuenta que la capa de base de datos de Django es meramente una interfaz a tu base de datos. Puedes acceder a tu base de datos mediante otras herramientas, lenguajes de programación o frameworks de bases de datos; no hay nada específico de Django sobre tu base de datos.
may 31, 2026