2011-06-23 32 views
0

我希望标题没有误导性。根据m2m字段进行查询的匹配数量

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

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

鉴于一个模型2实例的关键字是这样的:

keywords2 = model2_instance.keywords.all() 

我需要找回它至少有一个关键字是keywords2,类似的型号1实例:

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) 

必须有这样做的更快的方法。有任何想法吗?

回答

2

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

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_idmodel2_instance ID。这肯定会更快,更具可扩展性。

相关问题