社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Django

Django:检查记录是否存在于两个不同的状态

Joshua • 5 年前 • 1903 次点击  

我使用两种模型在用户之间构建聊天系统:

class Chat(models.Model):
    created = models.DateTimeField(auto_now_add=True)
class Participant(models.Model):
    chat = models.ForeignKey(Chat, on_delete=models.CASCADE, related_name='participants')
    sender = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    receiver = models.ForeignKey(CustomUser, on_delete=models.CASCADE)

参与者模型中的一条记录表示从用户发送者向用户接收者发送消息的能力。

因此,对于A和B之间的有效私人聊天,将存在两个记录,一个以AS发送方存在,另一个作为接收方,反之亦然。

由于一个用户将永远是启动聊天的第一个用户,而第一个参与者记录可以是AS发送者或B作为发送者,所以我需要知道是否有一个干净和廉价的方式来检查当用户尝试启动聊天时是否存在两个记录,并且如果存在聊天返回ID。

如何在同一查询中搜索记录的存在(发件人=A,接收器=B)和(发件人=B,接收器=A)?

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/52314
 
1903 次点击  
文章 [ 2 ]  |  最新文章 5 年前
Willem Van Onsem
Reply   •   1 楼
Willem Van Onsem    6 年前

你可以利用两个 JOIN 在这里,比如:

Chat.objects.filter(
    participants__sender=user_a,
    participants__receiver=user_b
).filter(
    participants__sender=user_b,
    participants__receiver=user_a
)

这将导致如下查询:

SELECT chat.id, chat.created
FROM chat
INNER JOIN participant ON chat.id = participant.chat_id
INNER JOIN participant T5 ON chat.id = T5.chat_id
WHERE participant.receiver_id = user_b AND participant.sender_id = user_a
  AND T5.receiver_id = user_a AND T5.sender_id = user_b

因此它将返回所有 Chat 两个这样的对象 Participant 对象存在。

不过,上述情况并不理想,因为我们做了两个 加入 s、 如果有 unique_together 对参与者的约束,如:

class Participant(models.Model):
    chat = models.ForeignKey(Chat, on_delete=models.CASCADE, related_name='participants')
    sender = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    receiver = models.ForeignKey(CustomUser, on_delete=models.CASCADE)

    class Meta:
        unique_together = ['sender', 'receiver']

我们可以数一数 参与者 对象,例如:

from django.db.models import Count, Q

Chat.objects.filter(
    Q(participants__sender=user_a, participants__receiver=user_b) |
    Q(participants__sender=user_b, participants__receiver=user_a)
).annotate(
    nparticipants=Count('participants')
).get(
    nparticipants=2
)

这将使用以下查询:

SELECT chat.id, chat.created, COUNT(participant.id) AS nparticipants
FROM chat
INNER JOIN participant ON chat.id = participant.chat_id
WHERE (participant.receiver_id = user_b AND participant.sender_id = user_a)
   OR (participant.receiver_id = user_a AND participant.sender_id = user_b)
GROUP BY chat.id
HAVING COUNT(participant.id) = 2

我们可以利用 .get(..) 这里,因为 独一无二 约束,保证最多有一个 聊天 对象,该对象将存在。这样我们就可以用 Chat.DoesNotExist 例外。

不过,我并不真的相信以上的模型是理想的。首先记录的数量将按比例增加 二次型 参加人数:三人有六项记录。此外 聊天 从概念上讲可能不是“定向的”:没有发送方和接收方,有两个或更多的对等方共享信息。

Iain Shelvington
Reply   •   2 楼
Iain Shelvington    6 年前

你可以用 Q 对象以创建复杂查询,包括在一个或另一个条件上进行匹配

query = Participant.objects.filter(Q(sender=A, receiver=B) | Q(sender=B, receiver=A))
query.count() == 2  # If you want to check that 2 records exist

| 在这种情况下,创建一个带有“或”的过滤器