/ / Django: como filtrar () depois de distinct () - django

Django: como filtrar () depois de distinct () - django

Se encadearmos uma chamada para filter () após uma chamada para distinct (), o filtro será aplicado à consulta antes do distinto. Como faço para filtrar os resultados de uma consulta depois de aplicando distinta?

Example.objects.order_by("a","foreignkey__b").distinct("a").filter(foreignkey__b="something")

A cláusula where no SQL resultante de filter () significa que o filtro é aplicado à consulta antes do distinct. Eu quero filtrar o queryset resultante do distinto.

Isso é provavelmente muito fácil, mas eu simplesmente não consigo descobrir e não consigo encontrar nada nele.

Editar 1:

Eu preciso fazer isso no ORM ...

SELECT z.column1, z.column2, z.column3 FROM ( SELECT DISTINCT ON (b.column1, b.column2) b.column1, b.column2, c.column3 FROM table1 a INNER JOIN table2 b ON ( a.id = b.id ) INNER JOIN table3 c ON ( b.id = c.id) ORDER BY b.column1 ASC, b.column2 ASC, c.column4 DESC ) z WHERE z.column3 = "Something";

(Eu estou usando o Postgres pelo caminho.) Então, eu acho que o que estou perguntando é "Como você aninha subconsultas no ORM? É possível?" Eu vou verificar a documentação.

Desculpe se eu não era específico anteriormente. Não ficou claro na minha cabeça.

Respostas:

2 para resposta № 1

Essa é uma pergunta antiga, mas ao usar o Postgres, você pode fazer o seguinte para forçar consultas aninhadas em suas linhas "Distintas":

foo = Example.objects.order_by("a","foreign_key__timefield").distinct("a")
bar = Example.objects.filter(pk__in=foo).filter(some_field=condition)

bar é a consulta aninhada conforme solicitado no OP sem recorrer a raw / extra etc. Testado a funcionar em 1.10, mas os documentos sugerem que deva funcionar pelo menos 1.7.

Meu caso de uso foi filtrar um relacionamento reverso. Se o Exemplo tiver alguma ForeignKey para modelar o Toast, você poderá fazer:

Toast.objects.filter(pk__in=bar.values_list("foreign_key",flat=true))

Isso fornece todas as instâncias do Toast em que o exemplo associado mais recente atende aos seus critérios de filtro.

Aviso de saúde grande sobre o desempenho, porém, usando esta barra se é provável que seja um enorme queryset você provavelmente vai ter um tempo ruim.


1 para resposta № 2

Não, você não pode fazer isso em um simples SELECT.
Como você disse nos comentários, no Django ORM filter é mapeado para a cláusula SQL WHEREe distinct mapeado para DISTINCT. E em um SQL, DISTINCT sempre acontece depois WHERE operando no conjunto de resultados, consulte Doc SQLite por exemplo.

Mas você poderia escrever subconsultas para aninhar SELECTs, isso depende do alvo real (eu não sei exatamente o que é seu agora ... você poderia elaborar mais?)

Além disso, para sua consulta, distinct("a") só mantém a primeira ocorrência de Example tendo o mesmo a, é isso que você quer?


1 para resposta № 3

Muito obrigado pela ajuda pessoal. Tentei as duas sugestões e não consegui dobrar nenhuma dessas sugestões para o trabalho, mas acho que isso me colocou na direção certa.

Acabei usando

from django.db.models import Max, F

Example.objects.annotate(latest=Max("foreignkey__timefield")).filter(foreignkey__timefield=F("latest"), foreign__a="Something")

Isso verifica o que é o mais recente foreignkey__timefieldé para cada Exemplo, e se for o mais recente e um = algo, então mantenha-o. Se não for o mais recente ou um! = Algo para cada Exemplo, então é filtrado.

Isso não aninha subconsultas, mas me dá a saída que estou procurando - e é bastante simples. Se há uma maneira mais simples, eu realmente gostaria de saber.