SlideShare une entreprise Scribd logo
1  sur  33
Exprimiendo el ORM
de Django
Héctor Pablos López
PyconES 2017
#whoami
Héctor Pablos López
Frontend developer @ StyleSage
www.stylesage.co
hector@stylesage.co
Contenido
• Introducción
• Expresiones (Query expressions)
• Joining
• Cuando todo lo demás falla
Introducción
Introducción
Why I hate the Django ORM: YouTube Video
https://www.youtube.com/watch?v=GxL9MnWlCwo
Rant alert
Introducción
Why I hate the Django ORM: YouTube Video
https://www.youtube.com/watch?v=GxL9MnWlCwo
Alex Gaynor
Desarrollador del ORM de Django
Introducción
• Es agnóstico en cuanto al motor de BD
• Escribimos consultas en alto nivel… Y en Python!
• Completamente integrado en Django (Migraciones,
modelos…)
¿Por qué usarlo?
Introducción
• El ORM como a mi me hubiera gustado que me lo
explicaran
• Ejemplos en Python Y SQL
Objetivo de esta charla
Introducción
Car.ojects.values(‘model_name’).filter(build_year__gt=1995)
SELECT car.model_name
FROM car
WHERE car.build_year > 1995;
Expresión básica
Expresiones
Expresiones
¿Qué son?
Un valor (simple o calculado) que se puede usar en una orden de DML
.filter(expression)
.order_by(expression)
.annotate(expression)
.aggregate(expression)
Expresiones
Objetos F()
Representan el valor de un campo
Car.ojects.filter(units_produced__gt=F(‘units_sold’))
SELECT *
FROM car
WHERE car.units_produced > car.units_sold
Expresiones
Objetos Q()
Encapsulan colecciones de argumentos con nombre
Car.ojects.filter(Q(kilometers__gt=1000) | Q(build_year__lt=1990))
SELECT *
FROM car
WHERE car.kilometers > 1000
OR car.build_year < 1990
Expresiones
annotate()
Anotar (dar nombre) a una expresión
Car.objects.annotate(plate=‘plate_number’)
SELECT plate_number AS plate
FROM car
Expresiones
Func() y Aggregate()
Funciones de nuestra base de datos… Las que queramos!
class DaysBetween(Func):
function = ‘DAYS_BETWEEN’
class Now(Func):
function = ‘NOW'
class Median(Aggregate):
function = ‘MEDIAN'
Expresiones
Combinar expresiones
Expresiones
Combinar expresiones
Funciones y más funciones
Company.objects 
.annotate(number_of_days=DaysBetween(Now(), F(‘date_started’))) 
.filter(number_of_days__lt=100)
SELECT DAYS_BETWEEN(NOW(), date_Started) AS number_of_days
FROM company
WHERE DAYS_BETWEEN(NOW(), date_Started) < 100;
Expresiones
Combinar expresiones
Funciones y más funciones… Agregadas!
Company.objects.values(‘region_id’) 
.annotate(all_the_days=Sum(DaysBetween(Now(), F(‘date_started’))))
SELECT SUM(DAYS_BETWEEN(NOW(), date_Started)) AS all_the_days
FROM company
GROUP BY region_id;
Expresiones
Combinar expresiones
Expresiones condicionales
Product.objects.annotate(
discounted_product_count=Count(
Case(
When(is_discounted=True, sold_out=False, then=F('id')),
default=None,
output_field=IntegerField()
),
distinct=True
)
)
Expresiones
Combinar expresiones
Product.objects.annotate(
discounted_product_count=Count(
[ … ]
),
avg_discount=Sum(
Case(
When(is_discounted=True, sold_out=True, then=F('discount_percent')),
default=0,
output_field=FloatField()
)
) / Case(
When(Q(discounted_product_count__gt=0), then=F('discounted_product_count')),
default=1,
output_field=IntegerField()
) / 100
)
Expresiones
Combinar expresiones
Joining
Joining
Con Foreign Key
class Parameter(models.Model):
name = models.CharField(max_length=30, unique=True)
parameter_category = models.ForeignKey(ParameterCategory)
affected_entities = models.ManyToManyField(
Entity,
blank=False,
help_text=‘Entities affected by this’,
)
Parameter.objects 
.values(‘name', 'parameter_category__name')
SELECT "parameter"."name",
"parametercategory"."name"
FROM "parameter"
INNER JOIN "parametercategory" ON
("parameter"."parameter_category_id" = "parametercategory"."id");
Joining
Con Foreign Key
class Parameter(models.Model):
name = models.CharField(max_length=30, unique=True)
parameter_category = models.ForeignKey(ParameterCategory)
affected_entities = models.ManyToManyField(
Entity,
blank=False,
help_text=‘Entities affected by this’,
)
Parameter.objects.values('name', ‘affected_entities__name')
SELECT "parameter"."name",
“entity"."name"
FROM "parameter"
LEFT OUTER JOIN “affected_entities"
ON ("parameter"."id" = "affected_entities"."parameter_id")
LEFT OUTER JOIN “entity"
ON ("affected_entites"."entity_id" = "entity"."id")
Joining
Foreign keys: select_related()
>> parameters = list(
Parameter.objects.values(‘name', ‘parameter_category__name’)
)
>> # Lista de diccionarios
>> parameters[0][‘parameter_category__name’]
u’Name of the category’
>> parameters = list(
Parameter.objects.select_related(‘parameter_category’)
)
>> # Lista de modelos. Accedemos a parameter_category sin consulta
>> # adicional
>> parameters[0].parameter_category.name
u’Name of the category’
Joining
ManyToMany fields: prefetch_related()
>> parameters = list(
Parameter.objects.values(‘name', ‘affected_entities__name’)
)
>> # Lista de diccionarios
>> parameters[0][‘affected_entities__name’]
u’Name of the entity’
>> parameters = list(
Parameter.objects.prefetch_related(‘affected_entities’)
)
>> # Lista de modelos. Accedemos a la lista de entidades sin consulta
>> # adicional
>> parameters[0].affected_entities.all()[0].name
u’Name of the category’
Joining
Sin Foreign Key
¯_(ツ)_/¯
Método extra()
Joining
Sin Foreign Key… Pero con modelos no gestionados por Django
class TableWithoutForeignKey(models.Model):
not_real = models.ForeignKey(OtherTable, db_column=‘other_column')
foo = models.CharField(max_length=50)
bar = models.IntegerField()
class Meta:
db_table = ‘table_without_foreign_key’
managed = False
Si todo lo demás falla
Si todo lo demás falla
RawSQL()
queryset.annotate(
val=RawSQL("select col from sometable where othercol = %s", (someparam,))
)
Añadir subqueries dentro del select
Si todo lo demás falla
extra()
Joins sin Foreign Key
QuerysetTable.extra(
where=[
'table_to_join_with.id = queryset_table.table_to_join_with_id'
],
tables = ['table_to_join_with'],
)
Si todo lo demás falla
Cursores
connection = connections[‘connnection_in_settings']
cursor = connection.cursor()
sql = """
SELECT
some_data,
some_other_data,
a_thing,
footer
FROM
THE_TABLE
WHERE
id=%s
AND code=%s
ORDER BY
column_to_order_by;
"""
cursor.execute(sql, [table_id_to_get, table_code_to_get])
desc = cursor.description
the_data_list = [
dict(zip([col[0].lower() for col in desc], row)) for row in cursor.fetchall()
]
#whoami
Héctor Pablos López
Frontend developer @ StyleSage
www.stylesage.co
hector@stylesage.co

Contenu connexe

Tendances

Tendances (20)

Python: Modules and Packages
Python: Modules and PackagesPython: Modules and Packages
Python: Modules and Packages
 
Intro to Python Programming Language
Intro to Python Programming LanguageIntro to Python Programming Language
Intro to Python Programming Language
 
Functions in Python
Functions in PythonFunctions in Python
Functions in Python
 
Extendiendo Django: Cómo Escribir Tu Propio Backend de Base de Datos - Exasol
Extendiendo Django: Cómo Escribir Tu Propio Backend de Base de Datos - ExasolExtendiendo Django: Cómo Escribir Tu Propio Backend de Base de Datos - Exasol
Extendiendo Django: Cómo Escribir Tu Propio Backend de Base de Datos - Exasol
 
Refactoring: Improve the design of existing code
Refactoring: Improve the design of existing codeRefactoring: Improve the design of existing code
Refactoring: Improve the design of existing code
 
PYTHON - TKINTER - GUI - PART 1.ppt
PYTHON - TKINTER - GUI - PART 1.pptPYTHON - TKINTER - GUI - PART 1.ppt
PYTHON - TKINTER - GUI - PART 1.ppt
 
Python Class | Python Programming | Python Tutorial | Edureka
Python Class | Python Programming | Python Tutorial | EdurekaPython Class | Python Programming | Python Tutorial | Edureka
Python Class | Python Programming | Python Tutorial | Edureka
 
Programación Orientada a Objetos para Python
Programación Orientada a Objetos para PythonProgramación Orientada a Objetos para Python
Programación Orientada a Objetos para Python
 
Chapter 1 - INTRODUCTION TO PYTHON -MAULIK BORSANIYA
Chapter 1 - INTRODUCTION TO PYTHON -MAULIK BORSANIYAChapter 1 - INTRODUCTION TO PYTHON -MAULIK BORSANIYA
Chapter 1 - INTRODUCTION TO PYTHON -MAULIK BORSANIYA
 
Pascal [modo de compatibilidad]
Pascal [modo de compatibilidad]Pascal [modo de compatibilidad]
Pascal [modo de compatibilidad]
 
What is Python? | Edureka
What is Python? | EdurekaWhat is Python? | Edureka
What is Python? | Edureka
 
MODELOS DE CALIDAD DEL SOFTWARE
MODELOS DE CALIDAD DEL SOFTWAREMODELOS DE CALIDAD DEL SOFTWARE
MODELOS DE CALIDAD DEL SOFTWARE
 
Introduction to the basics of Python programming (part 1)
Introduction to the basics of Python programming (part 1)Introduction to the basics of Python programming (part 1)
Introduction to the basics of Python programming (part 1)
 
Introduction to python
Introduction to pythonIntroduction to python
Introduction to python
 
Web development with Python
Web development with PythonWeb development with Python
Web development with Python
 
Packages In Python Tutorial
Packages In Python TutorialPackages In Python Tutorial
Packages In Python Tutorial
 
Object-oriented Programming in Python
Object-oriented Programming in PythonObject-oriented Programming in Python
Object-oriented Programming in Python
 
Python Tutorial Part 1
Python Tutorial Part 1Python Tutorial Part 1
Python Tutorial Part 1
 
Python Course | Python Programming | Python Tutorial | Python Training | Edureka
Python Course | Python Programming | Python Tutorial | Python Training | EdurekaPython Course | Python Programming | Python Tutorial | Python Training | Edureka
Python Course | Python Programming | Python Tutorial | Python Training | Edureka
 
File handling in Python
File handling in PythonFile handling in Python
File handling in Python
 

Similaire à Exprimiendo el ORM de Django

San Luis Oct 2008
San Luis Oct 2008San Luis Oct 2008
San Luis Oct 2008
guest02b440
 
Taller de Django betabeers
Taller de Django betabeersTaller de Django betabeers
Taller de Django betabeers
betabeers
 
5 Vb.Net
5 Vb.Net5 Vb.Net
5 Vb.Net
erinel
 

Similaire à Exprimiendo el ORM de Django (20)

San Luis Oct 2008
San Luis Oct 2008San Luis Oct 2008
San Luis Oct 2008
 
San Luis Oct 2008
San Luis Oct 2008San Luis Oct 2008
San Luis Oct 2008
 
Expediente Xpath #SEOnderground 2021
Expediente Xpath  #SEOnderground 2021Expediente Xpath  #SEOnderground 2021
Expediente Xpath #SEOnderground 2021
 
Introducción a Django
Introducción a DjangoIntroducción a Django
Introducción a Django
 
Taller de Django betabeers
Taller de Django betabeersTaller de Django betabeers
Taller de Django betabeers
 
Introducción a Django
Introducción a DjangoIntroducción a Django
Introducción a Django
 
Django
DjangoDjango
Django
 
Cuida tu código: Clean Code
Cuida tu código: Clean CodeCuida tu código: Clean Code
Cuida tu código: Clean Code
 
Tdd y clean code SG campus
Tdd y clean code SG campusTdd y clean code SG campus
Tdd y clean code SG campus
 
Testing efectivo con pytest
Testing efectivo con pytestTesting efectivo con pytest
Testing efectivo con pytest
 
Java fundamentos 15 consejos prácticos - ITLA Tech Day 2018
Java fundamentos   15 consejos prácticos - ITLA Tech Day 2018Java fundamentos   15 consejos prácticos - ITLA Tech Day 2018
Java fundamentos 15 consejos prácticos - ITLA Tech Day 2018
 
Django
DjangoDjango
Django
 
5 Vb.Net
5 Vb.Net5 Vb.Net
5 Vb.Net
 
Refactoring with php storm
Refactoring with php stormRefactoring with php storm
Refactoring with php storm
 
Google Hacking
Google HackingGoogle Hacking
Google Hacking
 
Combinación ganadora: Plone como CMS, tu framework preferido como frontend
Combinación ganadora: Plone como CMS, tu framework preferido como frontendCombinación ganadora: Plone como CMS, tu framework preferido como frontend
Combinación ganadora: Plone como CMS, tu framework preferido como frontend
 
Patrones de diseño.pptx
Patrones de diseño.pptxPatrones de diseño.pptx
Patrones de diseño.pptx
 
Frameworks de templates y xml
Frameworks de templates y xmlFrameworks de templates y xml
Frameworks de templates y xml
 
Introducción a Django
Introducción a DjangoIntroducción a Django
Introducción a Django
 
Semana 6 Estructura y Componentes
Semana 6   Estructura y ComponentesSemana 6   Estructura y Componentes
Semana 6 Estructura y Componentes
 

Dernier

redes informaticas en una oficina administrativa
redes informaticas en una oficina administrativaredes informaticas en una oficina administrativa
redes informaticas en una oficina administrativa
nicho110
 

Dernier (10)

Guia Basica para bachillerato de Circuitos Basicos
Guia Basica para bachillerato de Circuitos BasicosGuia Basica para bachillerato de Circuitos Basicos
Guia Basica para bachillerato de Circuitos Basicos
 
Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
 
redes informaticas en una oficina administrativa
redes informaticas en una oficina administrativaredes informaticas en una oficina administrativa
redes informaticas en una oficina administrativa
 
Innovaciones tecnologicas en el siglo 21
Innovaciones tecnologicas en el siglo 21Innovaciones tecnologicas en el siglo 21
Innovaciones tecnologicas en el siglo 21
 
How to use Redis with MuleSoft. A quick start presentation.
How to use Redis with MuleSoft. A quick start presentation.How to use Redis with MuleSoft. A quick start presentation.
How to use Redis with MuleSoft. A quick start presentation.
 
Buenos_Aires_Meetup_Redis_20240430_.pptx
Buenos_Aires_Meetup_Redis_20240430_.pptxBuenos_Aires_Meetup_Redis_20240430_.pptx
Buenos_Aires_Meetup_Redis_20240430_.pptx
 
Avances tecnológicos del siglo XXI y ejemplos de estos
Avances tecnológicos del siglo XXI y ejemplos de estosAvances tecnológicos del siglo XXI y ejemplos de estos
Avances tecnológicos del siglo XXI y ejemplos de estos
 
investigación de los Avances tecnológicos del siglo XXI
investigación de los Avances tecnológicos del siglo XXIinvestigación de los Avances tecnológicos del siglo XXI
investigación de los Avances tecnológicos del siglo XXI
 
Avances tecnológicos del siglo XXI 10-07 eyvana
Avances tecnológicos del siglo XXI 10-07 eyvanaAvances tecnológicos del siglo XXI 10-07 eyvana
Avances tecnológicos del siglo XXI 10-07 eyvana
 
EVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptx
EVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptxEVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptx
EVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptx
 

Exprimiendo el ORM de Django

  • 1. Exprimiendo el ORM de Django Héctor Pablos López PyconES 2017
  • 2. #whoami Héctor Pablos López Frontend developer @ StyleSage www.stylesage.co hector@stylesage.co
  • 3. Contenido • Introducción • Expresiones (Query expressions) • Joining • Cuando todo lo demás falla
  • 5. Introducción Why I hate the Django ORM: YouTube Video https://www.youtube.com/watch?v=GxL9MnWlCwo Rant alert
  • 6. Introducción Why I hate the Django ORM: YouTube Video https://www.youtube.com/watch?v=GxL9MnWlCwo Alex Gaynor Desarrollador del ORM de Django
  • 7. Introducción • Es agnóstico en cuanto al motor de BD • Escribimos consultas en alto nivel… Y en Python! • Completamente integrado en Django (Migraciones, modelos…) ¿Por qué usarlo?
  • 8. Introducción • El ORM como a mi me hubiera gustado que me lo explicaran • Ejemplos en Python Y SQL Objetivo de esta charla
  • 11. Expresiones ¿Qué son? Un valor (simple o calculado) que se puede usar en una orden de DML .filter(expression) .order_by(expression) .annotate(expression) .aggregate(expression)
  • 12. Expresiones Objetos F() Representan el valor de un campo Car.ojects.filter(units_produced__gt=F(‘units_sold’)) SELECT * FROM car WHERE car.units_produced > car.units_sold
  • 13. Expresiones Objetos Q() Encapsulan colecciones de argumentos con nombre Car.ojects.filter(Q(kilometers__gt=1000) | Q(build_year__lt=1990)) SELECT * FROM car WHERE car.kilometers > 1000 OR car.build_year < 1990
  • 14. Expresiones annotate() Anotar (dar nombre) a una expresión Car.objects.annotate(plate=‘plate_number’) SELECT plate_number AS plate FROM car
  • 15. Expresiones Func() y Aggregate() Funciones de nuestra base de datos… Las que queramos! class DaysBetween(Func): function = ‘DAYS_BETWEEN’ class Now(Func): function = ‘NOW' class Median(Aggregate): function = ‘MEDIAN'
  • 17. Expresiones Combinar expresiones Funciones y más funciones Company.objects .annotate(number_of_days=DaysBetween(Now(), F(‘date_started’))) .filter(number_of_days__lt=100) SELECT DAYS_BETWEEN(NOW(), date_Started) AS number_of_days FROM company WHERE DAYS_BETWEEN(NOW(), date_Started) < 100;
  • 18. Expresiones Combinar expresiones Funciones y más funciones… Agregadas! Company.objects.values(‘region_id’) .annotate(all_the_days=Sum(DaysBetween(Now(), F(‘date_started’)))) SELECT SUM(DAYS_BETWEEN(NOW(), date_Started)) AS all_the_days FROM company GROUP BY region_id;
  • 20. Expresiones Combinar expresiones Product.objects.annotate( discounted_product_count=Count( [ … ] ), avg_discount=Sum( Case( When(is_discounted=True, sold_out=True, then=F('discount_percent')), default=0, output_field=FloatField() ) ) / Case( When(Q(discounted_product_count__gt=0), then=F('discounted_product_count')), default=1, output_field=IntegerField() ) / 100 )
  • 23. Joining Con Foreign Key class Parameter(models.Model): name = models.CharField(max_length=30, unique=True) parameter_category = models.ForeignKey(ParameterCategory) affected_entities = models.ManyToManyField( Entity, blank=False, help_text=‘Entities affected by this’, ) Parameter.objects .values(‘name', 'parameter_category__name') SELECT "parameter"."name", "parametercategory"."name" FROM "parameter" INNER JOIN "parametercategory" ON ("parameter"."parameter_category_id" = "parametercategory"."id");
  • 24. Joining Con Foreign Key class Parameter(models.Model): name = models.CharField(max_length=30, unique=True) parameter_category = models.ForeignKey(ParameterCategory) affected_entities = models.ManyToManyField( Entity, blank=False, help_text=‘Entities affected by this’, ) Parameter.objects.values('name', ‘affected_entities__name') SELECT "parameter"."name", “entity"."name" FROM "parameter" LEFT OUTER JOIN “affected_entities" ON ("parameter"."id" = "affected_entities"."parameter_id") LEFT OUTER JOIN “entity" ON ("affected_entites"."entity_id" = "entity"."id")
  • 25. Joining Foreign keys: select_related() >> parameters = list( Parameter.objects.values(‘name', ‘parameter_category__name’) ) >> # Lista de diccionarios >> parameters[0][‘parameter_category__name’] u’Name of the category’ >> parameters = list( Parameter.objects.select_related(‘parameter_category’) ) >> # Lista de modelos. Accedemos a parameter_category sin consulta >> # adicional >> parameters[0].parameter_category.name u’Name of the category’
  • 26. Joining ManyToMany fields: prefetch_related() >> parameters = list( Parameter.objects.values(‘name', ‘affected_entities__name’) ) >> # Lista de diccionarios >> parameters[0][‘affected_entities__name’] u’Name of the entity’ >> parameters = list( Parameter.objects.prefetch_related(‘affected_entities’) ) >> # Lista de modelos. Accedemos a la lista de entidades sin consulta >> # adicional >> parameters[0].affected_entities.all()[0].name u’Name of the category’
  • 28. Joining Sin Foreign Key… Pero con modelos no gestionados por Django class TableWithoutForeignKey(models.Model): not_real = models.ForeignKey(OtherTable, db_column=‘other_column') foo = models.CharField(max_length=50) bar = models.IntegerField() class Meta: db_table = ‘table_without_foreign_key’ managed = False
  • 29. Si todo lo demás falla
  • 30. Si todo lo demás falla RawSQL() queryset.annotate( val=RawSQL("select col from sometable where othercol = %s", (someparam,)) ) Añadir subqueries dentro del select
  • 31. Si todo lo demás falla extra() Joins sin Foreign Key QuerysetTable.extra( where=[ 'table_to_join_with.id = queryset_table.table_to_join_with_id' ], tables = ['table_to_join_with'], )
  • 32. Si todo lo demás falla Cursores connection = connections[‘connnection_in_settings'] cursor = connection.cursor() sql = """ SELECT some_data, some_other_data, a_thing, footer FROM THE_TABLE WHERE id=%s AND code=%s ORDER BY column_to_order_by; """ cursor.execute(sql, [table_id_to_get, table_code_to_get]) desc = cursor.description the_data_list = [ dict(zip([col[0].lower() for col in desc], row)) for row in cursor.fetchall() ]
  • 33. #whoami Héctor Pablos López Frontend developer @ StyleSage www.stylesage.co hector@stylesage.co

Notes de l'éditeur

  1. Por qué odio el ORM de Django. En él ponen ejemplo de una agrupación muy sencilla que no se podía hacer en el momento de su charla, ahora sí se puede, pero a mi, personalmente, me molesta especialmente no poder hacer un join de dos tablas sin haber definido una foreign key para ellas. Pero os preguntaréis por qué comento este vídeo, si podría ser sólo un usuario cabreado, pues bien…
  2. Porque el autor de la charla es este chico Alex Gaynor, quien tiene una gran carrera, siendo uno de sus trabajos… Desarrollar el ORM de Django
  3. 1 - Es agnóstico en cuanto al motor de BD, es decir, podemos cambiar nuestro motor de base de datos y tendremos un impacto mínimo, o incluso ningún impacto en nuestro código. Es un poco mentira, porque luego intercambiar bases de datos sin ningún problema no es tan fácil. 2 - Escribimos consultas en alto nivel: Por ejemplo, podemos beneficiarnos del control de flujo de un lenguaje de programación de alto nivel para construir consultas de una manera mucho más sencilla que concatenando cadenas manualmente a una sentencia sql. Y ejecución lazy, y demás… 3 - Podemos gestionar la estructura de nuestra base de datos desde nuestro django, con la ventaja de tener la historia de la base de datos en control de versiones, la facilidad para hacer despliegues con cambios en la base de datos, etc…
  4. Es el tutorial de orm 2.0, donde termina el tutorial empieza esta charla.
  5. Una base de datos no sólo es capaz de devolvernos los datos que tiene almacenados, por lo que el ORM no es sólo para recibir diccionarios o modelos, también lo podemos utilizar para pedir que sea la base de datos la que procese los datos y nos devuelva resultados. Podemos tener bases de datos de Big Data
  6. Las expresiones pueden ser tan sencillas como una cadena que representa un campo del modelo, o pueden volverse tremendamente complejas. Lo que hay dentro de estas funciones son expresiones, pero un aggregate también es una expresión en si misma.
  7. F() representa el valor de un campo. Con F, por ejemplo, podemos comprar unos campos con otros, pero también realizar operaciones aritméticas.
  8. Encapsulan blablabla no significa nada, es lo que dice la documentación. Pero podemos decir que son trozos del Where, que suena mucho mejor. Sobre todo, usados para poder hacer condiciones con ORs. Se pueden usar igual que los objetos F(), para representar el valor de un campo. https://docs.djangoproject.com/en/1.11/ref/models/querysets/#django.db.models.Q https://docs.djangoproject.com/en/1.11/topics/db/queries/#complex-lookups-with-q
  9. Nos sirve para dar nombre a una expresión, que puede ser todo lo compleja que queramos. Pero esto no es sólo útil para hacer más manejable el query set resultante. También sirve para tener un nombre con el que referirnos a esa expresión en cualquier expresión posterior. https://docs.djangoproject.com/en/1.11/ref/models/querysets/#django.db.models.query.QuerySet.annotate
  10. También podemos crearnos nuestra propia librería de funciones de la base de datos. La gran mayoría de las funciones que nuestra base de datos tenga las podemos convertir a expresiones Func. También las agregadas. Aquí están ejemplos muy sencillos, pero se puede custodiar completamente el SQL generado por cada función, en caso de que su traducción no sea estándar. Eso sí, una vez cambiado el SQL nos podemos olvidar un poco de que nuestro código sea agnóstico respecto a la BD. https://docs.djangoproject.com/en/1.11/ref/models/expressions/#func-expressions
  11. Vemos que podemos usar funciones. Incluso funciones como parámetros de otras funciones. El ORM de Django se encarga traducir correctamente este SQL. Con annotate le damos un nombre al resultado de la función y lo podremos usar como cualquier otro parámetro. Filtrando, por ejemplo, las empresas que tengan menos de 100 días de existencia.
  12. Pero también podemos usar funciones dentro de funciones agregadas, aquí sumaríamos los días que lleva de existencia cada empresa.
  13. Y si añadimos las expresiones condicionales tenemos una potencia muy cercana a la de la base de datos. Aquí usamos funciones agregadas (Count), expresiones condicionales (Case y When) y un objeto F.
  14. Y si añadimos las expresiones condicionales tenemos una potencia muy cercana a la de la base de datos. Aquí usamos funciones agregadas (Count), expresiones condicionales (Case y When) y un objeto F. En vez de traerme 200 millones de productos y calcular, hago los cálculos en la base de datos.
  15. Y si añadimos las expresiones condicionales tenemos una potencia muy cercana a la de la base de datos. Aquí usamos funciones agregadas (Count), expresiones condicionales (Case y When) y un objeto F.
  16. Hacer joins en tablas referenciadas por claves foráneas o tablas intermedias es extremadamente fácil. simplemente hay que indicar los campos que nos interesan del resto de tablas y Django genera la consulta SQL correcta, con un inner join. https://docs.djangoproject.com/en/1.10/ref/models/querysets/#django.db.models.query.QuerySet.select_related
  17. Lo mismo con las relaciones many to many. En este caso vemos que, adecuadamente, se hace un outer join. Esto es muy potente y muy fácil de usar, mucho mejor que construir las sentencias SQL como cadenas, debemos aprovecharnos de ello. https://docs.djangoproject.com/en/1.10/ref/models/querysets/#django.db.models.query.QuerySet.select_related
  18. select_related() hace que, en una sola consulta, obtengamos todos los datos de la tabla relacionada con la categoría del parámetro y lo convierte a model, pudiendo acceder sin hacer queries adicionales a dichos datos https://docs.djangoproject.com/en/1.11/ref/models/querysets/#select-related
  19. prefetch_related() es lo mismo pero para relaciones many to many. Es muy útil, porque en lugar de tener una lista con información redundante de cada parámetro para cada entidad afectada (el producto cartesiano), tenemos un modelo para cada parámetro, que a su vez contiene una “lista” (ManyRelatedManager, actúa como un queryset) con cada uno de los modelos de entidades relacionados. https://docs.djangoproject.com/en/1.11/ref/models/querysets/#prefetch-related
  20. Se puede hacer, pero es una solución que requiere escribir SQL. Veremos la mejor opción en la siguiente sección.
  21. Muchas veces usamos bases de datos en nuestra app de Django que no se gestionan desde la app de Django. Es decir, Django no se encarga del DDL, no crea las tablas ni las modifica, incluso puede que no escriba, sólo lee datos. En este caso… Podemos definir la Foreign Key que queramos! Incluso aunque no sea real.
  22. Ejemplo de la documentación, perdemos agnosticismo con la base de datos, debemos usarlo con mucho cuidado si usamos alias de tablas y debemos escapar los parámetros si vienen del exterior.
  23. Con extra podemos, por ejemplo, hacer joins entre tablas que no tienen definida una foreign key en el modelo. Las condiciones del where, de hecho, pueden ser varias. El método extra() lleva siendo desaconsejado por los desarrolladores de Django desde hace mucho tiempo, se dice que se va a deprecar, pero nunca se hace, ya que es necesario para este tipo de casos.
  24. La opción última es ejecutar SQL plano, sin más mediante un cursor. En las líneas resaltada en amarillo cogemos la descripción del cursor (nombres de las columnas) para crear una lista de diccionarios, de la misma forma que si ejecutáramos un QuerySet en lugar de un cursor.