对于我想要的东西,区别可能是错误的,但我有一个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
并用它注释。我有点疯狂试图围绕细节扭曲我的大脑。在我的脑海中,感觉就像你应该能够做几行,但我只是看不出来。
答案 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或递归查询的连接)。