La meilleure option pour trouver des rangées où il y a es une ligne de jonction :
Report.objects.filter(user__isnull=False).distinct()
Il utilise un INNER JOIN
(et vérifie ensuite de manière redondante User.id
n'est pas nulle).
La meilleure option pour trouver des rangées où il y a des pas une ligne de jonction :
Report.objects.filter(user__isnull=True)
Cela rend LEFT OUTER JOIN
puis vérifie User.id
n'est pas nulle.
Les requêtes basées sur les jointures seront plus rapides que les sous-requêtes, ce qui est plus rapide que les nouvelles options disponibles, comme dans Django >= 3, pour trouver des lignes. sans une ligne de jonction :
Report.objects.filter(~Exists(User.objects.filter(report=OuterRef('pk'))))
Cela crée un WHERE NOT EXISTS (SELECT .. FROM User..)
implique donc un ensemble de résultats intermédiaires potentiellement important (merci @Tomasz Gandor).
Ceci pour Django <3, où filter()
ne peut pas recevoir de sous-requêtes, utilise également une sous-requête et est donc plus lent :
Report.objects.annotate(
no_users=~Exists(User.objects.filter(report=OuterRef('pk')))
).filter(no_users=True)
Cela peut être combiné avec des sous-requêtes. Dans cet exemple, une Textbook
a un certain nombre de Versions
(c'est-à-dire, version
a textbook_id
), et un version
a un certain nombre de Pages
(c'est-à-dire, page
a version_id
). La sous-requête obtient la dernière version de chaque manuel scolaire auquel sont associées des pages :
subquery = (
Version.objects
.filter(
# OuterRef joins to Version.textbook in outer query below
textbook=OuterRef('textbook'),
# excludes rows with no joined Page records
page__isnull=False)
# ordered so [:1] below gets highest (ie, latest) version number
.order_by('-number').distinct()
)
# Only the Version.ids of the latest versions that have pages returned by the subquery
books = Version.objects.filter(pk=Subquery(subquery.values('pk')[:1])).distinct()
Pour renvoyer les lignes qui ont une jointure avec l'une ou les deux tables, utilisez les objets Q ( Page
y TextMarkup
tous deux ont des clés étrangères annulables qui rejoignent File
):
from django.db.models import Q
File.objects.filter(Q(page__isnull=False) | Q(textmarkup__isnull=False).distinct()