簡體   English   中英

如何通過ManyToMany字段中帶注釋的屬性對查詢集進行排序

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM