[英]How to sort queryset by annotated attr from ManyToMany field
最簡單的例子:
class User(models.Model):
name = ...
class Group(models.Model):
members = models.ManyToManyField(User, through='GroupMembership')
class GroupMembership(models.Model):
user = ...
group = ...
我想獲取按成員的帶注釋字段排序的組列表。
我正在使用Trigram搜索來過濾和注釋用戶queryset。 要獲得帶注釋的用戶,我需要執行以下操作:
User.objects.annotate(...).annotate(similarity=...)
現在,我嘗試按用戶的“相似性”對“組”查詢集進行排序:
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')
但這是行不通的,因為prefetch_related
在Python中完成了“ joining”。 所以我有錯誤:
"FieldError: Cannot resolve keyword 'members' into field."
我希望您有一個通過trigram搜索及其Django綁定來實現名稱相似性的數據庫功能,或者您可以創建任何一個:
from django.db.models import Max, Func, Value, Prefetch
class Similarity(Func):
function = 'SIMILARITY'
arity = 2
SEARCHED_NAME = 'searched_name'
ann_users = User.objects.annotate(similarity=Similarity('name', Value(SEARCHED_NAME)))
qs = Group.objects.prefetch_related(Prefetch('members', queryset=ann_users))
qs = qs.annotate(
similarity=Max(Similarity('members__name', Value(SEARCHED_NAME)))
).order_by('similarity')
主查詢被編譯為
SELECT app_group.id, MAX(SIMILARITY(app_user.name, %s)) AS similarity
FROM app_group
LEFT OUTER JOIN app_groupmembership ON (app_group.id = app_groupmembership.group_id)
LEFT OUTER JOIN app_user ON (app_groupmembership.user_id = app_user.id)
GROUP BY app_group.id
ORDER BY similarity ASC;
-- params: ['searched_name']
它不是標題中所要的,但結果是相同的。
注意:SIMILARITY函數評估多少次效率取決於數據庫查詢優化器。 如果通過原始查詢(在某些簡化的情況下)的原始想法更好,那么EXPLAIN命令的查詢計划將是一個有趣的答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.