重新排序查询以根据发布日期将所有作者组合在一起并按降序排列

时间:2012-06-17 16:38:18

标签: django

我正在建立一个论坛,其中一个人发布消息,其他几个人回复它。

我有一个消息模型和响应模型如下:

class Messages (models.Model):
    author = models.ForeignKey(User)
    message = models.TextField()
    def __unicode__(self):
        return self.message

class Responses (models.Model):
    message = models.ForeignKey(Messages)
    responder = models.ForeignKey(User, related_name='responder')
    rsp_to = models.ForeignKey(User, related_name='rsp_to')
    rsp_from = models.ForeignKey(User, related_name='rsp_from')
    response = models.TextField()
    pub_date = models.DateTimeField('date_published')
    def __unicode__(self):
        return self.message

我想获得一个根据响应者组织的查询集,以便最新响应者的所有响应都是第一个,第二个最新响应者的响应是第二个,依此类推。

db表示例:

pk  message  responder  rsp_to  rsp_from  response  pub_date
------------------------------------------------------------
1    a        User.2  a.author   User.2    ....      1
2    a        User.3  a.author   User.3    ....      2
3    a        User.3  User.3    a.author   ....      3
4    a        User.4  a.author   User.4    ....      4
5    a        User.4  User.4    a.author   ....      5
6    a        User.2  User.2    a.author   ....      6
7    a        User.3  a.author   User.3    ....      7
8    a        User.3  User.3    a.author   ....      8
9    a        User.4  a.author   User.4    ....      9

重新排序的查询集:

pk  message  responder  rsp_to  rsp_from  response  pub_date
------------------------------------------------------------
9    a        User.4  a.author   User.4    ....      9
5    a        User.4   User.4   a.author   ....      5
4    a        User.4  a.author   User.4    ....      4
8    a        User.3   User.3   a.author   ....      8
7    a        User.3  a.author   User.3    ....      7
3    a        User.3   User.3   a.author   ....      3
2    a        User.3  a.author   User.3    ....      2
6    a        User.2   User.2   a.author   ....      6
1    a        User.2  a.author   User.2    ....      1

或者表示为:

r = [<all responses from latest responder>, <all responses from 2nd latest responder>,..., <all responses from earliest responder>]

如果我从:

开始
r = Responses.objects.filter(message="a").order_by('-pub_date')

我先得到最新的回复。如何重新排序查询集,以便来自最新唯一响应者的所有响应在查询集中首先分组,来自第二个唯一响应者的所有响应都分组到第二个,依此类推?

1 个答案:

答案 0 :(得分:0)

使用sorted()

让我们首先考虑使用旧的sorted()函数在Python中进行排序。它是comparison sort的一种类型,即它通过成对比较项目,一次一对,以及每一对决定哪一个应该首先进行排序。比较排序仅在比较器(作为排序参数给出的函数)定义total order

时有效
  1. 如果a≤b且b≤a则a = b(反对称,实际上不需要进行比较排序);
  2. 如果a≤b且b≤c则a≤c(传递性);
  3. a≤b或b≤a(总计)。
  4. 因此,如果您可以定义一个比较器,它从您的表中获取两行并决定哪一行先行,并且该比较器定义了一个总顺序,那么您只需使用该比较器调用sorted

    但是这样的比较器根本不存在你的问题。当两个不同的用户只考虑两行时,你永远不知道哪一个应该先出现。您将始终需要了解这些作者的最新帖子。结论:您无法使用sorted()

    使用SQL

    我不知道SQL是否可以处理这个问题。尝试并重写你的问题,省略所有Django和Python的东西,只有你拥有的表。如果您创建了这样的问题,请在此问题中添加一个链接。如果SQL可以处理它,那么您可以调用Responses.objects.sql()

    使用存储桶

    下面的代码是如何使用存储桶对您想要的方式进行排序的示例。我使用了一个虚拟类响应,专注于原则。

    from random import randint, shuffle
    
    # == Data definition ==
    class Response:
      user = None #int
      time = None #int
      def __str__(self):
        return '(%d:%2d)' % (self.user,self.time)
    
    # == Create random data ==
    responses = []
    for i in range(20):
      r = Response()
      r.user = randint(1,4)
      r.time = i
      responses.append(r)
    shuffle(responses)
    
    # == Put in buckets ==
    bucketdict = {}
    for r in responses:
      if r.user in bucketdict:
        bucketdict[r.user].append(r)
      else:
        bucketdict[r.user] = [r]
    
    # == create list from dict ==
    bucketlist = bucketdict.items()
    def printbucketlist():
      for user,user_rsps in bucketlist:
        print user, 
        for rsp in user_rsps:
          print rsp,
        print
      print
    printbucketlist()
    
    # == Sort responses within each bucket ==
    def rsp_comparator(r1,r2):
      return r2.time - r1.time
    for user,responses in  bucketlist:
      responses.sort(rsp_comparator)
    printbucketlist()
    
    # == Sort bucketlist ==
    def bucket_cmp(b1,b2):
      # assumes that the first response in the list has the highet time
      return b2[1][0].time - b1[1][0].time
    bucketlist = sorted(bucketlist,cmp=bucket_cmp)
    printbucketlist()
    
    # == Concatenate into one list ==
    sortedresponses = []
    for user, user_rsps in bucketlist:
      for response in user_rsps:
        sortedresponses.append(response)
    for response in sortedresponses:
      print response