exemple le plus simple:Comment trier queryset attr annotée du champ ManyToMany
class User(models.Model):
name = ...
class Group(models.Model):
members = models.ManyToManyField(User, through='GroupMembership')
class GroupMembership(models.Model):
user = ...
group = ...
Je veux obtenir la liste des groupes classés par domaine des membres annoté. J'utilise la recherche trigramme pour filtrer et annoter le jeu de requêtes utilisateur. Pour obtenir les utilisateurs annotés j'ai quelque chose comme ça:
User.objects.annotate(...).annotate(similarity=...)
Et maintenant, je suis en train de trier des groupes queryset par la « similitude » des utilisateurs:
ann_users = User.objects.annotate(...).annotate(similarity=...)
qs = Group.objects.prefetch_related(Prefetch('members',
queryset=ann_users))
qs.annotate(similarity=Max('members__similarity')).order_by('similarity')
Mais cela ne fonctionne pas, parce que prefetch_related
fait le 'joindre' en Python; donc j'ai l'erreur:
"FieldError: Cannot resolve keyword 'members' into field."
Merci pour votre réponse. J'ai ton idée. Malheureusement, je n'ai pas de fonction unique "Similarity"; ma recherche est plus compliquée - elle utilise la recherche Double Metaphone + Trigrams par plusieurs champs. –
Et une autre chose: je suppose que Similarity ne devrait pas être utilisé deux fois, n'est-ce pas? –
Si vous écrivez une expression de similarité, je peux la réécrire en une seule fonction. Une annotation ne peut pas être réutilisée par des champs connexes (ou je ne peux pas le faire). Les relations sont aux modèles pas aux requêtes ou aux queries. Par conséquent, il n'existe actuellement aucun moyen de réutiliser une annotation par un champ associé. Il est plus important de vérifier si le nombre d'évaluations de similarité est len (User) + len (GroupMembership) ou 2 * len (User), pour votre backend. Deux fois plus lent ORM qu'un SQL manuscrit n'est pas mauvais. – hynekcer