最简单的例子:
class User(models.Model):
name = ...
class Group(models.Model):
members = models.ManyToManyField(User, through='GroupMembership')
class GroupMembership(models.Model):
user = ...
group = ...
我希望得到按注释的成员字段排序的组列表。
我使用trigram搜索来过滤和注释用户查询集。 要获得带注释的用户,我有类似的东西:
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中进行'加入';所以我有错误:
"FieldError: Cannot resolve keyword 'members' into field."
答案 0 :(得分:0)
我希望你有一个数据库函数,用于通过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命令的查询计划将是一个有趣的答案。