2011-04-04 17 views

Respuesta

12

La mayoría de las veces, solo hay un posible conjunto de resultados para una consulta.

El uso para encadenar filtros viene cuando se trata de M2M:

Considera:

# 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.

+3

Otro ejemplo: no se limita a m2m, esto también puede ocurrir con uno-a-muchos, con la búsqueda inversa, por ejemplo usando el related_name en ForeignKey – wim

+0

¡Gracias por su explicación! Antes de eso, pensé que el último y el segundo ejemplo son iguales, por lo que el último ejemplo no me resultó útil (resultados de búsqueda erróneos) y pasé mucho tiempo buscando. Segundo ejemplo muy útil para mí. También, como dijo Wim, esto se puede usar con relaciones inversas de uno a muchos como en mi caso. – zen11625

6

Puede usar el módulo de conexión para ver las consultas sql sin procesar para comparar. Según lo explicado por 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) 
>>> 
-2

hay una diferencia cuando se tiene petición 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 request

Author.objects.filter(book_name='name1').filter(book_name='name2') 

devuelve los autores que tienen libros con tanto 'tipo1' y 'tipo2'

para más detalles Mira https://docs.djangoproject.com/en/dev/topics/db/queries/#s-spanning-multi-valued-relationships

+5

'Author.objects.filter (book_name = 'name1', book_name = 'name2')' ni siquiera es válido python, sería 'SyntaxError: argumento de palabra clave repetido' – wim

+0

¿Dónde se define book_name exactamente? ¿Te refieres a book_set__name? – DylanYoung

38

Como se puede ver en las sentencias SQL generadas la diferencia no es el " O "como algunos pueden sospechar". Es cómo se coloca WHERE y JOIN.

Ejemplo 1 (la misma tabla combinada): desde 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á a todos los blogs que tienen una anotación con (entry__headline__contains='Lennon') AND (entry__pub_date__year=2008), que es lo que se espera de esta consulta.

Resultado:

Book 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 resultado. Porque primero filtra todos los blogs con (entry__headline__contains='Lennon') y luego desde los filtros de resultado (entry__pub_date__year=2008).

La diferencia es que también le dará resultados como:

libro con

{entry.headline: '**Lennon**', entry.pub_date: 2000}, 
{entry.headline: 'Bill', entry.pub_date: **2008**} 

Una tabla: Pero si la consulta no implica tablas combinadas como el ejemplo de Yuji y DTing. El resultado es el mismo

+8

Supongo que estoy muy densa esta mañana, pero esta frase me confunde: "Porque primero filtra todos los blogs con' (entry__headline__contains = 'Lennon') 'y luego desde los filtros de resultados' (entry__pub_date__year = 2008) '" If "luego del resultado" es exacto, ¿por qué incluirá algo con 'entry.headline == 'Bill'' ... no' entry__headline__contains =' Lennon'' filtrará la instancia 'Bill'? –

8

El caso en que los resultados de "varios argumentos filtro de consulta" es diferente a "encadenado-filter-consulta", siguiente:

Selecting referenced objects on the basis of referencing objects and relationship is one-to-many (or many-to-many).

Multiple filters:

Referenced.filter(referencing1_a=x, referencing1_b=y) 
    # same referencing model ^^    ^^ 

Chained filters:

Referenced.filter(referencing1_a=x).filter(referencing1_b=y) 

Both queries can output different result:
If more then one rows in referencing-model Referencing1 can refer to same row in referenced-model Referenced . This can be the case in Referenced : Referencing1 have either 1:N (one to many) or N:M (many to many) relation-ship.

Ejemplo:

Considere mi solicitud my_company tiene dos modelos Employee y Dependent. Un empleado en my_company puede tener más de 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, suponiendo que marido y mujer no pueden trabajar en un my_company. Tomé 1: m ejemplo

modelo referenciado Así, se Employee que puede ser referenciado por más de Dependent que hace referencia a un modelo. Ahora consideremos relación de 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 | 
       +------+--------+-------------+--------------+ 

Dependent a1 refers to employee A , and dependent b1, b2 references to employee B .

Ahora mi pregunta es:

Buscar todos los empleados que tienen hijo/hija tiene marcas de distinción (por ejemplo> = 75%), tanto en la universidad y la escuela?

>>> Employee.objects.filter(dependent__school_mark__gte=75, 
...       dependent__college_mark__gte=75) 

[<Employee: A>] 

salida es 'A' depende 'a1' tiene marcas de distinción tanto en la universidad y la escuela depende de los empleados '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:

Employee (school_mark >=75 AND college_mark>=75)Dependent

En segundo lugar, si necesito una consulta:

Encontrar todos los empleados cuyos algunas de las personas dependientes tiene 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 seleccionada debido a 'B' tiene dos niños (más de uno!), Uno tiene marca de distinción en la escuela 'B1' y otro es tiene marca de distinción en la universidad 'B2'.
Orden de filtro no importa también podemos escribir por encima de consulta como:

>>> Employee.objects.filter(
...    dependent__college_mark__gte=75 
...    ).filter(
...    dependent__school_mark__gte=75) 

[<Employee: A>, <Employee: B>] 

resultado es igual!álgebra relacional puede ser:

(Employee (school_mark >=75)Dependent) (college_mark>=75)Dependent

nota que sigue:

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) 

Salidas mismo resultado: [<Dependent: a1>]

verifico objetivo consulta SQL generada por Django usando print qd1.query y print qd2.query ambos son iguales (Django 1.6) .

Pero semánticamente ambos son diferentes a . primero se parece a simple sección σ [school_mark> = 75 Y college_mark> = 75] (dependiente) y segundo como consulta anidada lento: σ [school_mark> = 75] [college_mark> = 75] (Dependiente)).

Si uno necesita Code @codepad

por cierto, se le da en la documentación @Spanning multi-valued relationships simplemente he añadido un ejemplo, creo que va a ser útil para alguien nuevo.

+1

Gracias por esta útil explicación, es mejor que la de la documentación que no está nada clara. – wim

+0

La última marca sobre filtrar los Dependientes directamente es muy útil. Muestra que el cambio en los resultados solo ocurre definitivamente cuando pasas por una relación de muchos a muchos. Si consulta una tabla directamente, encadenar filtros es como peinar dos veces. – Chris

6

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 mencionó en "Effective Django ORM",

  • QuerySets maintain state in memory
  • Chaining triggers cloning, duplicating that state
  • Unfortunately, QuerySets maintain a lot of state
  • If possible, don’t chain more than one filter
0

Si al final de esta página buscando la manera de construir dinámicamente una django queryset con múltiples filtros de encadenamiento, pero necesita que los filtros sean delTipoen lugar de OR, considere usar Q objects.

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) 
Cuestiones relacionadas