Django 如何对我的对话模式进行适当的筛选?

Django 如何对我的对话模式进行适当的筛选?,django,django-models,Django,Django Models,我有两个简单的模型: class Message(BaseModel): src = models.ForeignKey('Personne', related_name='message_src') dst = models.ForeignKey('Personne', related_name='message_dst') is_read = models.BooleanField(default=False) message = models.TextFie

我有两个简单的模型:

class Message(BaseModel):
    src = models.ForeignKey('Personne', related_name='message_src')
    dst = models.ForeignKey('Personne', related_name='message_dst')
    is_read = models.BooleanField(default=False)
    message = models.TextField(null=True, blank=True,
                               verbose_name=_(u'Messages'))
class Conversation(BaseModel):

    personnes = models.ManyToManyField(Personne, related_name='conversations')
    messages = models.ManyToManyField(Message, related_name='conversations')
我被任命为
人员
a
ManyToManyField
(而不仅仅是
src
dst
),这样我就可以拥有对话所需的任何
人员

我的问题是当我有两个这样的人时:

p_src = Personne.objects.get(user=self.request.user)
# i've got id_dst somewhere before
p_dst = Personne.objects.get(pk=id_dst)
我想找回“只有那两个人的对话”

目前我正在做的是:

c = Conversation.objects.filter(
    personnes__in=[p_src, p_dst]).distinct()
但是结果看起来像是“两个人中有一个人的谈话”

我应该怎么做?

这应该可以:

c = Conversation.objects.filter(personnes=p_src).filter(personnes=p_dst).distinct()

要实现这一点,您需要两个步骤。首先,确保
Personne
的计数等于要匹配的
Personne
的数量。然后针对每个
人员
实例筛选该字段:

from django.db.models import Count

personnes = [p_src, p_dst]
result = Conversation.objects.annotate(c=Count('personnes')).filter(c=len(personnes))
for personne in personnes:
    result = result.filter(personnes=personne)

这里有一个有效的解决方案,根本没有优化,所以如果你有其他更好的解决方案,我就是你的人

# filter all conversations where there are 2 participants and
# (1) src is part of them
convs_src = Conversation.objects.annotate(c=Count('personnes'))\
    .filter(c=2)\
    .filter(personnes__in=[p_src])
# (2) dst is part of them
convs_dst = Conversation.objects.annotate(c=Count('personnes'))\
    .filter(c=2)\
    .filter(personnes__in=[p_dst])
# ... then take the intersection, which should always be "one":
convs = set(list(convs_src)).intersection(list(convs_dst))
if len(convs):  # get() = pour avoir un objet (!= QuerySet)
    c = Conversation.objects.get(pk=convs[0])
else:
    raise Exception('should never ever happen')

我会尝试找到所有的对话,其中p_src和p_dst扮演着某种角色

conversations_where_two_are_in = Conversations.objects.all().filter(
    Q(personnes = p_src)|
    Q(personnes = p_dst)
)
扔掉所有其他人参与的对话。我会找到除了这两个我们感兴趣的人以外的所有人,并把他们列在一个名单上

list_of_other_personnes = Personnes.objects.all().exclude(
    personnes = p_src,
    personnes = p_dst,
)
我会把他们排除在我们两人的谈话之外

conversations_between_only_two = conversations_where_two_are_in.exclude(
    personnes__in = list_of_other_personnes)

我希望它能帮助你。请让我知道不是这样。

试着删除
->
中的
..filter(personnes=[p\u src,p\u dst])。distinct()
如果我尝试(已经完成了
:)
)我得到:
int()参数必须是字符串或数字,而不是“list”
我正在考虑做相反的事情:从Person开始,比如“给我这两个人所有对话的交集”如果我尝试你的解决方案,我会有一个明显的Python错误:“关键字参数重复”,如果我尝试
c=Conversation.objects.filter(personnes=p_src.filter(personnes=p_dst.distinct())
I get
'QuerySet'对象没有“personnes”属性
对。我编辑了我的答案。尝试链接
过滤器
确定?错误看起来像是您试图访问
…过滤器(personnes=p_src)。persones
您确定
p_src
Personne
模型吗(创建一个只有外键的空模型给
用户
)。因为在这种情况下,消息是合乎逻辑的:您不能询问“组”“=persones只等于一个
Person
model我不知道,但它不一定有效。我刚刚使用了您的
count
anotate
示例使我自己的版本有效(参见我的答案).所以我给你投票,这样你就不会投反对票了。但是你真的尝试过你的解决方案吗?你能说明什么不起作用吗?我没有你的确切模型设置,但我以前用过。你可以只做一个empy Personne模型,有一个字段:userHi的外键,你做3个查询,我的解决方案做2个。我不知道哪一个是最快的。你怎么认为?