Django模型上的独特风格过滤

时间:2011-04-15 09:36:19

标签: django django-models django-queryset

对于我想要的东西,区别可能是错误的,但我有一个Message类,如下所示,用于用户之间的简单平面消息传递系统:

class Message(models.Model):
    thread = models.ForeignKey(Thread)
    from_user = models.ForeignKey(User, related_name='messagefromuser')
    to_user = models.ForeignKey(User, related_name='messagetouser')
    when = models.DateTimeField(auto_now_add=True)
    message = models.TextField()

这允许两个用户聊聊单个Thread对象。该系统旨在允许两个用户在单独的线程上进行单独的对话。

就这样,我可以通过以下查询获取给定用户所涉及的消息:

Message.objects.filter( Q(from_user=u) | Q(to_user=u) )

输出用户发送或接收的每条消息。我正在构建一个页面,用户可以通过线程分组查看与其他用户的所有对话。这是我能想象到的理想输出:

[
    {
        'thread': thread_instance,
        'conversations': [
            {
                'other_user': user_instance
                'latest_reply': date_time_instance
            },
            ....
        ]
    },
    ...
]

我考虑过从顶部迭代这个,但除非有办法将Thread过滤到Message的{​​{1}},to_user字段,否则只有线程太多了。数据库服务器会融化。

  • from_user
  • 对邮件进行“分组”
  • 按其他用户“分组”,以便每个群组位于两个不同的用户之间,每Thread
  • 采用最新的Thread并用它注释。

我有点疯狂试图围绕细节扭曲我的大脑。在我的脑海中,感觉就像你应该能够做几行,但我只是看不出来。

1 个答案:

答案 0 :(得分:0)

threads = Thread.objects.filter(
  Q(message_set__from_user=u) | Q(message_set__to_user=u)
).order_by('id')

messages = Message.objects.filter(
  Q(thread__in=threads) & Q(Q(thread__from_user=u) | Q(thread_to_user=u))
).order_by('thread__id', '-when').select_related('from_user', 'to_user')

from itertools import groupby

t_index = 0
for thread_messages in groupby(messages, lambda x: x.thread_id):
  if threads[t_index].id is thread_messages[0].thread_id:
    threads[t_index].messages = thread_messages

  t_index += 1

这可能看起来有点复杂或可怕,但它应该做你想做的事情。从本质上讲,它首先查询所有线程,以便我们可以找出我们传达的线程。然后它找到那些线程的所有相关消息。

两个查询都按相同的字段排序,因此在代码的下半部分我们只能遍历列表一次,而不需要嵌套的for循环来查找具有正确id的每个线程。它们也都通过相同的查询(至少关于线程对象)进行过滤,以确保我们只返回此查询的相关结果。

最后,我们收到的消息被组合在一起并附加到每个线程;它们将按每个线程的降序显示。

最后,你可能还想重新排序线程以首先显示最新的线程,很容易在Thread模型上假设'when'字段:

threads = sorted(threads,key = lambda x:x.when,reverse = True)

通过使用上述方法,您每次都必须进行2次查询,无论是线程,还是消息。但它永远不会超过这个(注意对相关对象的select_related或递归查询的连接)。