我的Person
模型有ManyToMany
到Tags
。
我试图获取所有标记组合,并列出具有唯一这些标记的人。
E.g:
Tags a b c d
Person 1 has tags a and b
Person 2 has tags a
Person 3 has tags c
Person 4 has tags a b and c
我想要的是:
Tag A: Person 2
Tag B: None
Tag C: Person 3
Tag D: None
Tags [A, B]: Person 1
Tags [A, C]: None
Tags [A, D]: None
Tags [B, C]: None
Tags [B, D]: None
Tags [C, D]: None
Tags [A, B, C]: Person 4
Tags [A, B, D]: None
(etc.)
使用itertools.combinations
我可以迭代所有代码,例如:
for L in range(0, len(tag_list)+1):
for tag_combination in combinations(tag_list, L):
print(Person.objects.filter(tag__name__in=tag_list))
但上述问题(在print()
声明中)是人4将弹出"标签A","标签B",标签C&# 34;,"标签[A,B]","标签[A,C]","标签[B,C]",&# 34;标签[B,D]","标签[C,D]","标签[A,B,C]"等等,而我只希望此人列在"标签[A,B,C]"。
知道如何最好地接近这个吗?
答案 0 :(得分:0)
您可以直接查询M2M表并在人员和标签之间建立映射:
from collections import defaultdict
people_to_tags = defaultdict(list)
for tag_id, person_id in Person.tags.through.objects.all().values_list('tag_id', 'person_id'):
people_to_tags[person_id].append(tag_id)
然后,只需反映映射:
tags_to_people = defaultdict(list)
for person_id, tags in people_to_tags.items():
tags_to_people[tuple(tags)].append(person_id)
您只需要人数为1的行:
tag_to_person = {tag_id: people[0] for tag_id, people in tags_to_people.items() if len(people) == 1}