¿Cuál es la diferencia entre el filtro con múltiples argumentos y el filtro de cadena en django?
¿Cuál es la diferencia entre el filtro con múltiples argumentos y el filtro de cadena en django?
Respuestas:
Como puede ver en las declaraciones SQL generadas, la diferencia no es el "O" como algunos sospechan. Así es como se colocan WHERE y JOIN.
Example1 (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 te 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 incluye 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 implica tablas unidas como el ejemplo de Yuji y DTing. El resultado es el mismo.
(entry__headline__contains='Lennon')
y luego desde los filtros de resultados (entry__pub_date__year=2008)
" Si "luego del resultado" es correcto, ¿por qué incluirá algo con entry.headline == 'Bill'
.. .¿no entry__headline__contains='Lennon'
filtraría la Bill
instancia?
El caso en el que los resultados de "consulta de filtro de argumentos múltiples" es diferente de "consulta de filtro encadenado", siguiente:
La selección de objetos referenciados sobre la base de los objetos de referencia y la relación es de uno a muchos (o de muchos a muchos).
Varios 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 más de una fila en el modelo deReferencing1
referencia puede hacer referencia a la misma fila en el modelo de referenciaReferenced
. Este puede ser el caso enReferenced
:Referencing1
tener una relación 1: N (uno a muchos) o N: M (muchos a muchos).
Ejemplo:
Considere que mi aplicación my_company
tiene dos modelos Employee
y Dependent
. Un empleado my_company
puede tener más de dependientes (en otras palabras, un dependiente puede ser hijo / a de un solo empleado, mientras que un empleado puede tener más de un hijo / hija).
Ehh, asumiendo que, como marido-mujer, ambos no pueden trabajar en a my_company
. Tomé el ejemplo 1: m
Por lo tanto, Employee
es un modelo de referencia que puede ser referenciado por más de Dependent
ese modelo de referencia. Ahora considere el estado de relación 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 | +------+--------+-------------+--------------+
Dependiente se
a1
refiere al empleadoA
y dependienteb1, b2
al empleadoB
.
Ahora mi consulta es:
¿Encuentra todos los empleados que tienen un hijo / hija con 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 tanto en la universidad como en la escuela depende del empleado 'A'. Tenga en cuenta que 'B' no se selecciona porque ninguno de los hijos 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 lugar, caso necesito una consulta:
¿Encontrar todos los empleados cuyos dependientes tengan marcas de distinción 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 el otro tiene una marca de distinción en la universidad 'b2'.
El orden del 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>]
¡el resultado es el mismo! El álgebra relacional puede ser:
(Empleado ⋈ (marca_escuela> = 75) Dependiente) ⋈ (marca_universidad> = 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)
Produce el mismo resultado: [<Dependent: a1>]
Verifico la consulta SQL de destino generada por Django usando print qd1.query
y print qd2.query
ambos son iguales (Django 1.6).
Pero semánticamente ambos son diferentes para mí . primero se ve como una sección simple σ [marca_escuela> = 75 Y marca_universidad> = 75] (Dependiente) y la segunda como una consulta anidada lenta: σ [marca_escuela> = 75] (σ [marca_universidad> = 75] (Dependiente)).
Si uno necesita Code @codepad
por cierto, se da en la documentación @ Abarcando relaciones de múltiples valores . Acabo de agregar un ejemplo, creo que será útil para alguien nuevo.
La mayoría de las veces, solo hay un conjunto posible de resultados para una consulta.
El uso para encadenar filtros 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.
La diferencia de rendimiento es enorme. Pruébalo y verás.
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 mantienen mucho estado
- Si es posible, no encadene más de un filtro
Puede usar el módulo de conexión para ver las consultas SQL sin procesar para comparar. Como explica Yuji, 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 al final de esta página buscando la manera de construir dinámicamente un conjunto de consultas Django con varios filtros de encadenamiento, pero necesita los filtros para ser del AND
tipo en lugar de OR
, considere el uso de 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)
Si requiere ayb entonces
and_query_set = Model.objects.filter(a=a, b=b)
si requiere a así como b entonces
chaied_query_set = Model.objects.filter(a=a).filter(b=b)
Documentos oficiales: https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
Publicación relacionada: Encadenando múltiples filtros () en Django, ¿es esto un error?
Hay una diferencia cuando tiene una solicitud a 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 el 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 obtener más detalles, consulte https://docs.djangoproject.com/en/dev/topics/db/queries/#s-spanning-multi-valued-relationships
Author.objects.filter(book_name='name1',book_name='name2')
ni siquiera es python válido, lo seríaSyntaxError: keyword argument repeated