【问题标题】:How to get last message between current user and others?如何获取当前用户和其他人之间的最后一条消息?
【发布时间】:2015-12-16 20:50:39
【问题描述】:

我有一个 消息 django-model,带有字段:

  • id(主键)
  • user_sender(用户实例的外键)
  • user_receiver(用户实例的外键)
  • send_date(日期时间)
  • 消息(字符)
  • 状态(布尔值)

所以,我正在尝试获取当前用户和其他用户之间的所有最新消息。

例子:

如果我有 3 个用户:

约翰向莎拉发送消息(17.08.2015) (id=1)

莎拉向约翰发送消息(20.08.2015) (id=2)

John 向 Max (18.08.2015) (id=3) 发送消息

我只需要获取 ID 为 2 和 3 的消息。

我正在尝试此查询,但收到所有 3 条消息:

Message.objects.filter(
            Q(user_sender_id=1) |
            Q(user_receiver_id=1)).\
order_by('user_sender', 'user_receiver', '-send_date').\
distinct('user_sender', 'user_receiver')

那么,我做错了什么?为什么在使用外键不同后我收到 3 条消息?

UPD #1:

class Message(models.Model):
    """
    Model for user messages.
    - Who
    - Whom
    - When
    - Message
    - Status
    """
    user_sender = models.ForeignKey(User, related_name="sender")
    user_receiver = models.ForeignKey(User, related_name="receiver")
    send_date = models.DateTimeField(auto_now_add=True)
    message = models.CharField(max_length=500)
    status = models.BooleanField(default=False)

    def __unicode__(self):
        return u'%s %s ->%s' % (self.send_date, self.user_sender, self.user_receiver)

【问题讨论】:

  • 请展示您的模型的真实代码
  • 如果您想通过此查询获取消息 2 和 3,那么您正在寻找来自或来自 John 的消息。但是消息 1 也来自 John。
  • @Pynchia 更新问题。
  • @Ivan 还有什么?您能提供丢弃重复外键对的解决方案吗?
  • @Ivan 说您的查询不符合您的要求。应该是Message.objects.filter(user_sender_id=1).latest('send_date')

标签: python sql django postgresql python-2.7


【解决方案1】:

获取当前用户和其他用户之间的所有最新消息:

def is_latest(qs, message):
    # if contact exist in sent and received
    # take lastmessage contact
    if qs:
        if message.send_date < qs[0].send_date:
            return False
    return True

user = User.objects.get(id = 1)
sent = Message.objects.filter(user_sender=user).order_by('user_receiver','-send_date').distinct('user_receiver') 
received = Message.objects.filter(user_receiver=user).order_by('user_sender','-send_date').distinct('user_sender') 
messages = list(chain(sent, received))
contact_list = []
for message in messages:
    if message.user_sender == user:
        c = message.user_receiver                
        if not is_latest(received.filter(user_sender=c), message): continue
    else:
        c = message.user_sender
        if not is_latest(sent.filter(user_receiver=c), message): continue

    contact_list.append({'id':c.id,'email': c.email,'last_message': message.message})

print(contact_list)

【讨论】:

    【解决方案2】:
    sent = Message.objects.filter(user_sender_id=1).order_by('-send_date')[:1]
    received = Message.objects.filter(user_receiver_id=1).order_by('-send_date')[:1]
    
    from itertools import chain
    
    messages = list(chain(sent, received))
    

    【讨论】:

    • 看起来不错,但不能完全成功。我正在使用带有消息的数据库对其进行测试,但似乎总是只收到 2 条消息?为什么要抛弃别人?
    • 因为 [:1] 对于每个查询集*只会收到一条消息。如果您希望收到最后五条消息,只需将第二个查询集中的 [:1] 更改为 [:5]
    • 哇!比看起来很棒。标记为答案并睡觉,明天将测试它。谢谢你:)
    • 它看起来不像我需要的那样工作。它选择所有消息,但我只需要当前用户和其他用户之间的一个(最新)。
    • 发送和接收的查询集,带[:1],只会带一条消息,可以显示你的查询集代码吗?
    猜你喜欢
    • 2017-04-10
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 2021-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多