queryset - models py python
diferencia entre filtro con argumentos múltiples y filtro de cadena en django (7)
¿Cuál es la diferencia entre filtro con múltiples argumentos y filtro de cadena en django?
Como puede ver en las sentencias SQL generadas, la diferencia no es el "OR", como algunos pueden sospechar. Es cómo se coloca WHERE y JOIN.
Ejemplo1 (la misma tabla unida): de https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
Blog.objects.filter(
entry__headline__contains=''Lennon'',
entry__pub_date__year=2008)
Esto le dará todos los blogs que tienen una entrada con ambos (entry__headline__contains=''Lennon'') AND (entry__pub_date__year=2008)
, que es lo que esperaría de esta consulta.
Resultado:
Blog with {entry.headline: ''Life of Lennon'', entry.pub_date: ''2008''}
Ejemplo 2 (encadenado)
Blog.objects.filter(
entry__headline__contains=''Lennon''
).filter(
entry__pub_date__year=2008)
Esto cubrirá todos los resultados del Ejemplo 1, pero generará un poco más de resultado. Porque primero filtra todos los blogs con (entry__headline__contains=''Lennon'')
y luego desde los filtros de resultados (entry__pub_date__year=2008)
.
La diferencia es que también le dará resultados como:
Un solo blog con múltiples entradas
{entry.headline: ''**Lennon**'', entry.pub_date: 2000},
{entry.headline: ''Bill'', entry.pub_date: **2008**}
Cuando se evaluó el primer filtro, el libro se incluyó debido a la primera entrada (aunque tiene otras entradas que no coinciden). Cuando se evalúa el segundo filtro, el libro se incluye debido a la segunda entrada.
Una tabla: pero si la consulta no involucra tablas unidas como el ejemplo de Yuji y DTing. El resultado es el mismo
El caso en el que los resultados de "múltiples argumentos filtro-consulta" es diferente a "encadenado-filtro-consulta", a continuación:
La selección de objetos referenciados sobre la base de referenciar objetos y relaciones es de uno a muchos (o de muchos a muchos).
Múltiples filtros:
Referenced.filter(referencing1_a=x, referencing1_b=y) # same referencing model ^^ ^^
Filtros encadenados:
Referenced.filter(referencing1_a=x).filter(referencing1_b=y)
Ambas consultas pueden generar resultados diferentes:
Si hay más de una fila en el modelo deReferencing1
,Referencing1
puede hacer referencia a la misma fila en el modeloReferenced
que se haceReferenced
. Este puede ser el caso enReferenced
:Referencing1
tiene relación de 1: N (de uno a muchos) o de N: M (de muchos a muchos).
Ejemplo:
Considere mi aplicación my_company
tiene dos modelos Employee
y Dependent
. Un empleado de my_company
puede tener más que dependientes (en otras palabras, un dependiente puede ser hijo / hija de un solo empleado, mientras que un empleado puede tener más de un hijo / hija).
Ehh, asumiendo que esposo y esposa no pueden trabajar en my_company
. Tomé el ejemplo 1: m
Por lo tanto, se hace referencia al Employee
: modelo al que se puede hacer referencia en más de un Dependent
que hace referencia al modelo. Ahora considere relación-estado de la siguiente manera:
Employee: Dependent: +------+ +------+--------+-------------+--------------+ | name | | name | E-name | school_mark | college_mark | +------+ +------+--------+-------------+--------------+ | A | | a1 | A | 79 | 81 | | B | | b1 | B | 80 | 60 | +------+ | b2 | B | 68 | 86 | +------+--------+-------------+--------------+
El dependiente
a1
refiere al empleadoA
y las referencias dependientesb1, b2
al empleadoB
Ahora mi consulta es:
Buscar todos los empleados que tienen hijo / hija tiene marcas de distinción (digamos> = 75%) tanto en la universidad como en la escuela.
>>> Employee.objects.filter(dependent__school_mark__gte=75,
... dependent__college_mark__gte=75)
[<Employee: A>]
La salida es ''A'' dependiente ''a1'' tiene marcas de distinción en la universidad y la escuela depende del empleado ''A''. La nota ''B'' no está seleccionada porque el hijo menor de ''B'' tiene marcas de distinción tanto en la universidad como en la escuela. Álgebra relacional:
Empleado ⋈ (school_mark> = 75 AND college_mark> = 75) Dependiente
En Segundo caso, necesito una consulta:
¿Encuentra a todos los empleados cuyas personas a su cargo tienen marcas distintivas en la universidad y la escuela?
>>> Employee.objects.filter(
... dependent__school_mark__gte=75
... ).filter(
... dependent__college_mark__gte=75)
[<Employee: A>, <Employee: B>]
Esta vez ''B'' también se seleccionó porque ''B'' tiene dos hijos (¡más de uno!), Uno tiene una marca de distinción en la escuela ''b1'' y otro tiene una marca de distinción en la universidad ''b2''.
El orden de filtro no importa, también podemos escribir la consulta anterior como:
>>> Employee.objects.filter(
... dependent__college_mark__gte=75
... ).filter(
... dependent__school_mark__gte=75)
[<Employee: A>, <Employee: B>]
resultado es lo mismo! El álgebra relacional puede ser:
(Empleado ⋈ (school_mark> = 75) Dependiente) ⋈ (college_mark> = 75) Dependiente
Nota siguiente:
dq1 = Dependent.objects.filter(college_mark__gte=75, school_mark__gte=75)
dq2 = Dependent.objects.filter(college_mark__gte=75).filter(school_mark__gte=75)
Resultados del mismo resultado: [<Dependent: a1>]
Compruebo la consulta SQL de destino generada por Django utilizando print qd1.query
e print qd2.query
son los mismos (Django 1.6).
Pero, semánticamente, ambos son diferentes a mí . primero se ve como la sección simple σ [marca_escuela> = 75 Y marca_de_universidad> = 75] (Dependiente) y la segunda como consulta anidada lenta: σ [marca_escuela> = 75] (σ [marca_de_agricultura> = 75] (Dependiente)).
Si necesitas Code @codepad
Por cierto, se presenta en la documentación @ https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships Acabo de agregar un ejemplo, creo que será útil para alguien nuevo.
Hay una diferencia cuando tiene una solicitud para su objeto relacionado, por ejemplo
class Book(models.Model):
author = models.ForeignKey(Author)
name = models.ForeignKey(Region)
class Author(models.Model):
name = models.ForeignKey(Region)
solicitud
Author.objects.filter(book_name=''name1'',book_name=''name2'')
devuelve un conjunto vacío
y solicitud
Author.objects.filter(book_name=''name1'').filter(book_name=''name2'')
devuelve autores que tienen libros con ''nombre1'' y ''nombre2''
para más información, consulte https://docs.djangoproject.com/en/dev/topics/db/queries/#s-spanning-multi-valued-relationships
La diferencia de rendimiento es enorme. Pruébalo y mira.
Model.objects.filter(condition_a).filter(condition_b).filter(condition_c)
es sorprendentemente lento en comparación con
Model.objects.filter(condition_a, condition_b, condition_c)
Como se menciona en "Effective Django ORM" ,
- QuerySets mantiene el estado en la memoria
- El encadenamiento desencadena la clonación, duplicando ese estado
- Desafortunadamente, QuerySets mantiene un montón de estado
- Si es posible, no encadene más de un filtro
La mayoría de las veces, solo hay un posible conjunto de resultados para una consulta.
El uso de filtros de encadenamiento se produce cuando se trata de m2m:
Considera esto:
# will return all Model with m2m field 1
Model.objects.filter(m2m_field=1)
# will return Model with both 1 AND 2
Model.objects.filter(m2m_field=1).filter(m2m_field=2)
# this will NOT work
Model.objects.filter(Q(m2m_field=1) & Q(m2m_field=2))
Otros ejemplos son bienvenidos.
Puede usar el módulo de conexión para ver las consultas en sql sin procesar para comparar. Como explicó Yuji''s, en su mayor parte son equivalentes como se muestra aquí:
>>> from django.db import connection
>>> samples1 = Unit.objects.filter(color="orange", volume=None)
>>> samples2 = Unit.objects.filter(color="orange").filter(volume=None)
>>> list(samples1)
[]
>>> list(samples2)
[]
>>> for q in connection.queries:
... print q[''sql'']
...
SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL)
SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL)
>>>
Si termina en esta página buscando cómo construir dinámicamente un queryset django con múltiples filtros de encadenamiento, pero necesita que los filtros sean del tipo AND
lugar de OR
, considere usar objetos Q.
Un ejemplo:
# First filter by type.
filters = None
if param in CARS:
objects = app.models.Car.objects
filters = Q(tire=param)
elif param in PLANES:
objects = app.models.Plane.objects
filters = Q(wing=param)
# Now filter by location.
if location == ''France'':
filters = filters & Q(quay=location)
elif location == ''England'':
filters = filters & Q(harbor=location)
# Finally, generate the actual queryset
queryset = objects.filter(filters)