代码之家  ›  专栏  ›  技术社区  ›  user2896120

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

  •  1
  • user2896120  · 技术社区  · 6 年前

    我有三张桌子。用户、发布和共享。post是一个包含所有post的表。post与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)
    

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

    Post表

    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这样做。结果应该是post 1和post 2,因为用户发布了post 1,还共享了来自用户2的post 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]
    

    我在做最后一行后得到这个错误:

    类型错误:“nonetype”和的实例之间不支持“<” '非类型'

    我怎样才能做到这一点?为什么我会得到这个错误?

    2 回复  |  直到 6 年前
        1
  •  1
  •   willeM_ Van Onsem    6 年前

    我觉得你做得很复杂。您的收藏包含的核心问题在这里 元素类型 Post share 我真的建议你 这样做,因为这只会使处理它变得更困难。

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

    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 或由共享 一些用户 . 接下来,我们用 shared_or_created 包含共享时间的字段,如果未共享(由用户创建),则为创建时间。最后,我们按降序对该属性进行排序。

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

        2
  •  0
  •   iacob    6 年前

    您收到此错误是因为在最后一行中,您试图根据键进行排序 get_ts ,但(至少)两个元素 combined None 作为他们的价值 盖茨 ,因此无法进行比较。