121 votes

Comment puis-je trouver l'union de deux ensembles de requêtes Django ?

J'ai un modèle Django avec deux méthodes de gestion personnalisées. Chacune renvoie un sous-ensemble différent des objets du modèle, en fonction d'une propriété différente de l'objet.

Existe-t-il un moyen d'obtenir un queryset, ou simplement une liste d'objets, qui soit l'union des querysets renvoyés par chaque méthode de gestion ?

3 votes

(D'une réponse supprimée) Voir cette question pour une variation qui fonctionne avec des ensembles de requêtes provenant de différents modèles : stackoverflow.com/questions/431628/

1 votes

À partir de la version 1.11, les ensembles de requêtes django ont une méthode d'union intégrée. Je l'ai ajouté en tant que réponse pour une référence future.

216voto

Jordan Reiter Points 8679

Cela fonctionne et semble un peu plus propre :

records = query1 | query2

Si vous ne voulez pas de doublons, alors vous devrez ajouter .distinct() :

records = (query1 | query2).distinct()

8 votes

Alors que la réponse acceptée renvoie une union itérable (liste pour être exact), comme l'a demandé OP, cette méthode renvoie une véritable union de querysets. Ce queryset peut être exploité ultérieurement, ce qui est souhaité dans de nombreuses circonstances.

5 votes

En raison d'un bogue de Django, cette construction peut parfois renvoyer des résultats incorrects lorsqu'elle traite les données suivantes ManyToManyField s. Par exemple, vous verrez parfois que records.count() sera supérieure à query1.count() + query2.count() ce qui est clairement incorrect.

4 votes

@Jian pouvez-vous préciser la version de django avec le bug et un lien vers le problème djangoproject ?

66voto

Manu Points 741

À partir de version 1.11 Les querysets de django ont une méthode d'union intégrée.

q = q1.union(q2) #q will contain all unique records of q1 + q2
q = q1.union(q2, all=True) #q will contain all records of q1 + q2 including duplicates
q = q1.union(q2,q3) # more than 2 queryset union

Voir mon article de blog sur ce sujet pour plus d'exemples.

0 votes

Je n'ai pas réussi à faire fonctionner all=True. J'ai fini par transformer mon queryset en un ensemble avant de le renvoyer au client.

1 votes

@BradenHolt, all=True, signifie qu'il contiendra des enregistrements en double. Vous pouvez simplement supprimer all=True pour éviter de le transformer en un ensemble.

0 votes

Après cela, DjangoFilterBackend ne fonctionne pas, comment puis-je utiliser l'union et DjangoFilterBackend ?

8voto

Xianxing Points 71

Je suggère d'utiliser 'query1.union(query2)' au lieu de 'query1 | query2' ; J'ai obtenu des résultats différents avec les deux méthodes ci-dessus et la première est celle que j'attendais. Voici ce que j'ai trouvé :

print "union result:"
for element in query_set1.union(query_set2):
    print element

print "| result:"
for element in (query_set1 | query_set2):
    print element

résultat :

union result:
KafkaTopic object
KafkaTopic object
KafkaTopic object
KafkaTopic object
KafkaTopic object

| result:
KafkaTopic object
KafkaTopic object

1 votes

Veuillez coller du code, pas des images de code. Le texte des images n'est pas consultable, vous ne pouvez pas le copier/coller dans votre éditeur pour vérification, et il prend plus de place que nécessaire. Utilisez des backticks pour marquer le code comme tel, afin qu'il soit formaté correctement. Consultez le lien "aide" situé à côté de la zone de saisie du texte.

0 votes

Merci pour la mise à jour :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X