按基于m2m字段的查询匹配数排序

时间:2011-06-23 17:00:23

标签: django django-models django-queryset

我希望这个标题不会产生误导。

无论如何,我有两个模型,都与第三个模型有m2m关系。

class Model1: keywords = m2m(Keyword)
class Model2: keywords = m2m(Keyword)

给出Model2实例的关键字如下:

keywords2 = model2_instance.keywords.all()

我需要检索至少包含关键字2中的关键字的Model1实例,例如:

Model1.objects.filter(keywords__in=keywords2)

并按匹配关键字的数量对它们进行排序(不要认为可能通过'in'字段查找)。问题是,我该怎么做?

我正在考虑只是手动地对每个Model1实例进行交互,将它们附加到每个匹配的结果字典中,但是我需要这个来扩展,比如数万条记录。以下是我的想象:

result = {}
keywords2_ids = model2.keywords.all().values_list('id',flat=True)
for model1 in Model1.objects.all():
    keywords_matched = model1.keywords.filter(id__in=keywords2_ids).count()
    objs = result.get(str(keywords_matched), [])
    result[str(keywords_matched)] = objs.append(obj)

必须有更快的方法来做到这一点。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

您可以切换到原始SQL。您要做的是为Model1编写自定义manager,以根据关键字匹配计数返回Model1对象的有序ID组。 SQL很简单,就是在关键字id上连接两个多对多的表(Django自动创建一个表来表示多对多的关系),然后在{1} sql函数的Model1 id上进行分组。然后在这些计数上使用COUNT子句将生成所需的已排序ORDER BY id列表。在MySQL中,

Model1

此处SELECT appname_model1_keywords.model1_id, count(*) as match_count FROM appname_model1_keywords JOIN appname_model2_keywords ON (appname_model1_keywords.keyword_id = appname_model2_keywords.keyword_id) WHERE appname_model2_keywords.model2_id = model2_object_id GROUP BY appname_model1_keywords.model1_id ORDER BY match_count model2_object_id ID。这肯定会更快,更具可扩展性。