26

Funciones extras del ORM de Django

112852Puntos

hace 5 años

El ORM (Object-relational mapping) de Django es una herramienta poderosa y tal vez uno de los puntos más fuertes del framework. Nos facilita todo lo relacionado a consultas, actualización, eliminar, listar todo lo almacenado en nuestra base de datos de una manera fácil de entender.

Pero nuestros queries pueden ser más poderosos o sencillos de escribir con algunas características o funciones built-in de Django.

Q Objects

Una de las razones principales por las cuales querrías usar los objetos Q en los querys de Django es para incluir AND o OR.

Un ejemplo sencillo puede ser el buscador de Platzi, donde no solo queremos buscar por el nombre del curso, si no también por el nombre de la persona quien lo dicta.

Una opción común para lograr esto es:

Course.objects.filter(name_contains='django').filter(teacher_contains='Leonidas")

Pero con los Q Objects sería:

Course.objects.filter(
    Q(name__contains='django') |
    Q(teacher__contains='Leonidas')
)

Con esto, por ejemplo, obtendremos los cursos que tengan en su nombre la palabra Django o cursos donde Leonidas haya sido el instructor.

Si quisieras incluir ambas condiciones puedes sustituir el signo | (OR) por & (AND).

F Expression

Las expresiones F() pueden ser usadas para referenciar una columna o un campo del modelo en un query. Tal vez, por alguna razón, Platzi quiere aumentar los precios en sus suscripciones o el costo de los cursos individuales.

Podría hacerse con un query como este:

courses = Course.objects.all()
for course in courses:
    course.price *= 5
    course.save()

Pero también se podría hacer de esta forma:

from django.db.models import F

Course.objects.update(price=F('price') * 5)

O tal vez para un solo objeto:

django = Course.objects.get(pk=64)
django.price = F('price') * 5
django.save()

Aggregate y Annotate

Ambos nos dan varias funciones para realizar: Avg, Count, Max, Min, FloatField, Sum.

Aggregate genera un resultado de valores sobre todo un QuerySet, si quisiéramos traer el promedio general del rating de todos los cursos podríamos hacer:

Course.objects.all().aggregate(rating_avg=Avg('rating'))
{'rating_avg'=5}

Esto nos devolverá un diccionario con el promedio general del rating de todos los cursos.

Y Annotate generará un resultado de valores por cada elemento de nuestro QuerySet. Si quisiéramos conocer cuántas clases tiene cada curso podemos realizar el siguiente query:

q = Course.objects.annotate(classes_num=Count('classes'))
q[0].classes_num
35

q[1].classes_num
60

q es nuestro QuerySet de cursos, pero cada uno de ellos tiene ahora tiene nuestra variable classes_num para poder ver el número que queremos.

Mucho más sobre esto se puede leer en la documentación.

select_related y prefect_related

select_related es usado cuando vas a seleccionar un solo objeto con relaciones OneToOneField o ForeignKey. Django cachea en memoria los resultados evaluados con el mismo objeto QuerySet por ejemplo algo como esto:

courses = Course.objects.all().select_related('teacher')
for course in courses:
    print(course.teacher.name)

first_course = courses[1]
print(first_course.teacher.name)

La primera línea hará la consulta en la base de datos una sola vez y los resultados se guardarán en caché, será un solo query con INNER JOIN. Las demás líneas no harán una nueva consulta a la base de datos.

prefetch_related es usado cuando vas a obtener un conjunto de datos como con ManyToManyField o ForeignKey en reverso. Tiene el mismo propósito que select_related de tener una posible lluvia de consultas causada por acceder a objetos con relaciones.


Puedes aprender mucho más sobre Django y crear una increíble API con un setup en Docker listo para producción en el Curso Avanzado de Django.

Kevin
Kevin
iKenshu

112852Puntos

hace 5 años

Todas sus entradas
Escribe tu comentario
+ 2
Ordenar por:
4
24298Puntos

Para mi Django es un framework con muchas extra pilas, capas de hacer cosas tan exitosas como Platzi. Solo hay que tener un poco de imaginación.

Muy bien explicado.

2
9292Puntos

Excelente aporte Kevin.

Muchas gracias.