django - 如何查询仅描述的对象存在于多对多字段中的位置

Posted

技术标签:

【中文标题】django - 如何查询仅描述的对象存在于多对多字段中的位置【英文标题】:django - How to query where just the described objects exist in a many to many field 【发布时间】:2013-12-20 04:20:39 【问题描述】:

如何检查thread是否只包含sender(用户1)和recipient(用户2),而没有其他用户。

models.py

class Thread(models.Model):
    user = models.ManyToManyField(User)
    is_hidden = models.ManyToManyField(User, related_name='hidden_thread', blank=True)

class Message(models.Model):
    thread = models.ForeignKey(Thread)
    sent_date = models.DateTimeField(default=datetime.now)
    sender = models.ForeignKey(User)
    body = models.TextField()
    is_hidden = models.ManyToManyField(User, related_name='hidden_message', blank=True)

我试过了

>>> Thread.objects.filter(user=user1&user2)
>>> Thread.objects.filter(user=user1|user2)
# Both gave me an error:  Unsupported operand.

# Then this
>>> Thread.objects.filter(Q(user=user1) & Q(user=user2))
# Which gave me no threads at all.

# Then this
>>> Thread.objects.filter(Q(user=user1) | Q(user=user2)).distinct()
# Gave me threads of both the users.

我想要的是只检查指定用户的线程。假设用户 1 想向用户 2 发送消息。我想要的是,首先检查两个用户之间是否存在线程。如果有,请获取该线程,或者创建一个新线程。这怎么可能?最好的方法是什么。请帮我。谢谢。

请告诉我|& 有什么区别?因为我对这两个有非常不同的结果。

编辑:

>>> t1 = Thread.objects.get(id=1)
>>> t1
[<User: a>,<User: b>]
>>> t2 = Thread.objects.get(id=2)
>>> t2
[<User: a>,<User: b>,<User: c>]
>>> t3 = Thread.objects.get(id=3)
>>> t3
[<User:a>,<User: c>]
>>> t4 = Thread.objects.get(id=4)
>>> t4
[<User:a>,<User:b>]

我想要的是获得只有用户a 和用户b 存在的线程,而没有其他用户。在这种情况下,它将是:t1t4。希望我说清楚了。谢谢。

【问题讨论】:

|or&amp;and。我现在没有时间弄清楚如何进行实际查询,但至少这部分很容易回答。 Thread.objects.filter(Q(user=user1) &amp; Q(user=user2))中的Q是什么 用于复杂查询。见this 【参考方案1】:
excludedUsers = Users.objects.exclude(id__in=[user1.id, user2.id])
Thread.objects.filter(users=user1).filter(users=user2).exclude(users__in=excludedUsers)

【讨论】:

谢谢!我没有想到过滤用户的线程然后再次过滤另一个用户。它确实返回两​​个用户都存在的消息,但线程还包括其他用户以及该线程中的其他用户。我想排除其他用户存在的线程。 您可以使用 exclude 排除所有其他用户。 您是否尝试在末尾添加排除以删除包含其他用户的所有线程? 您好!对不起,我的连接很糟糕。请你详细说明这个[all other user objects]。我不明白如何实现它。再次感谢。 您好,感谢您的回答。但我收到一个错误id__in not defined... :(【参考方案2】:

假设,用户 1 想向用户 2 发送消息。我想要的是, 首先检查两个用户之间是否有线程。

请记住,过滤器会返回一个列表,所以如果有多个 同一用户之间的线程,你会得到多个结果。

如果你使用的是 postgresql,你可以使用这个语法,它只会返回不同的线程(消除重复的线程):

threads = Message.objects.filter(sender=user1) \
                         .filter(thread__user=user2)
                         .distinct('thread')

如果没有,那么你需要自己过滤掉重复项:

thread_ids = set(Message.objects.filter(sender=user1) \
                         .filter(thread__user=user2)
                         .values_list('thread__pk', flat=True))
threads = list(Thread.objects.get(pk=i) for i in thread_ids)

if not threads:
    # create a new thread
else:
    # Choose from one of the existing threads

现在您有了这两个用户的独特线程;您需要消除所有有其他人的线程:

threads.filter(user__in=[user1, user2])

【讨论】:

感谢您的回答。我现在正在使用 sqlite3。但是,当我尝试执行此threads = list(Thread.objects.get(pk=i) for i in thread_ids) 时,出现错误:TypeError: int() argument must be a string or number, not a 'tuple' 谢谢。是的,线程确实既包括用户,也包括其他用户。请看我的编辑。再次感谢。 我更新了我的答案,但我觉得可能有一种更简洁的方法可以通过自定义管理器来做到这一点。 threads.filter(user__in=[user1, user2]) 将返回包含至少这两个用户的线程。需要发生的是threads.exclude(user__in=[all other users]

以上是关于django - 如何查询仅描述的对象存在于多对多字段中的位置的主要内容,如果未能解决你的问题,请参考以下文章

Django ORM - 通过模型查询多对多?

Django查询集不包括多对多对象

Django 查询集过滤具有相同多对多字段的对象

Django - 查询列表中的任何项目在多对多字段中的任何对象

多对多查询的 Django 模型文件更新

如何在双连接关系之后在 Django 中执行查询(或:如何绕过 Django 对多对多“通过”模型的限制?)