将查询合并为一个,然后按日期排序

时间:2018-07-15 07:11:51

标签: python django

我有3张桌子。用户,发布和共享。帖子是包含所有帖子的表格。 Post与Share有一对多的关系。就是说,Share表是一个表,它指示用户共享了哪些帖子。这是表格的结构:

class Post(models.Model):
    user        = models.ForeignKey(User, on_delete=models.CASCADE)
    status      = models.CharField(max_length=200)

    share_count = models.IntegerField(default=0)

    created_at  = models.DateTimeField(auto_now_add=True)
    url         = models.CharField(max_length=150)

class Share(models.Model):
    post        = models.ForeignKey(Post, on_delete=models.CASCADE)
    user        = models.ForeignKey(User, on_delete=models.CASCADE)
    shared_at   = models.DateTimeField(auto_now_add=True)

我想要的是一个查询,该查询获取用户共享的帖子和用户创建的帖子。例如,假设我们有相同的数据:

发布表

id    user    status    share_count    created_at    url
1      1       hello         32         2017-06-01   hello
2      2       What's up     22         2017-07-01   whats-up

共享表格

post    user   shared_at
2       2      2017-07-02

我想要一个查询,该查询将获取用户的共享帖子及其帖子。假设我要为用户1这样做。结果应该是帖子1和帖子2,因为该用户发布了帖子1,还共享了用户2的帖子2。这是到目前为止的内容: 从itertools导入链中

user = User.objects.get(pk=1) # pick a user

own_posts = user.post_set.order_by('-created_at')
shared_posts = user.share_set.order_by('-shared_at')

combined = itertools.chain(own_posts, shared_posts)

def get_ts(obj):
   try:
     return obj.created_at
   except AttributeError:
     return obj.shared_at

last_5 = sorted(combined, key=get_ts, reverse=True)[:5]

我在执行最后一行后得到此错误:

  

TypeError:“ NoneType”实例与“   “ NoneType”

我该如何进行这项工作?为什么会出现此错误?

2 个答案:

答案 0 :(得分:1)

我认为您使其变得非常复杂。核心问题在这里,您的集合包含两种类型的元素Postshare。我真的建议您不要这样做,因为这样做只会使处理起来更加困难。

但是,我们可以构建例如一个查询集,该查询集将返回由用户发布或由该用户共享的帖子。例如:

from django.db.models import Q
from django.db.models.functions import Coalesce

Post.objects.filter(
    Q(user=some_user) | 
    Q(share__user=some_user)
).annotate(
    shared_or_created=Coalesce('share__shared_at', 'created_at')
).order_by('-shared_or_created')

因此,现在我们有了由some_user创建或由some_user分享的帖子列表。接下来,我们用shared_or_created字段注释每个帖子,该字段包含共享的时间,或者在不共享(由用户创建)的情况下,包含创建的时间。最后,我们按降序对该属性进行排序。

将其编码为查询的优点在于它是在数据库级别处理的。此外,它仍然是一个查询集,因此您可以在其上添加额外的过滤器,切片等。

答案 1 :(得分:0)

您收到此错误,是因为您在最后一行中尝试基于键get_ts进行排序,但是(至少)combined的两个元素的值是None get_ts,因此无法比较。