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

Django:按子对象的属性排序对象

  •  2
  • cwj  · 技术社区  · 16 年前

    考虑模型:

    class Author(models.Model):
        name = models.CharField(max_length=200, unique=True)
    
    class Book(models.Model):
        pub_date = models.DateTimeField()
        author = models.ForeignKey(Author)
    

    现在假设我想按出版日期订购所有的书。我会用 order_by('pub_date')

    想想看,这真的很简单。基本上是:

    • 最上面的作者是最近出版一本书的作者
    • 等等。

    我可能会一起破解一些东西,但由于这可能会变得很大,我需要知道我做得对。

    谢谢你的帮助!

    编辑: 最后,在每本书中添加一个新字段以显示最后一本书的日期,并更新整个时间是否更好?

    5 回复  |  直到 16 年前
        1
  •  0
  •   isagalaev    16 年前

    最后,在每本书中添加一个新字段以显示最后一本书的日期,并更新整个时间是否更好?

    事实上会的!这是一种正常的非规范化实践,可以这样做:

    class Author(models.Model):
        name = models.CharField(max_length=200, unique=True)
        latest_pub_date = models.DateTimeField(null=True, blank=True)
    
        def update_pub_date(self):
            try:
                self.latest_pub_date = self.book_set.order_by('-pub_date')[0]
                self.save()
            except IndexError:
                pass # no books yet!
    
    class Book(models.Model):
        pub_date = models.DateTimeField()
        author = models.ForeignKey(Author)
    
        def save(self, **kwargs):
            super(Book, self).save(**kwargs)
            self.author.update_pub_date()
    
        def delete(self):
            super(Book, self).delete()
            self.author.update_pub_date()
    

    • 在SQL中使用联接和分组执行此操作
    • 将所有书籍放到Python端并删除重复的书籍

    这两个选项都选择在读取发布日期时从标准化数据计算发布日期。在编写新数据时,反规范化会对每个作者执行此计算。其想法是,大多数web应用程序的读写次数最多,因此这种方法更可取。

    这样做的一个明显的缺点是,基本上你在不同的地方有相同的数据,这需要你保持同步。它通常会吓死人:-)。但这通常不是问题,除非您使用ORM模型来处理dat(您可能会这样做)。在Django中,是应用程序控制数据库,而不是相反。

    另一个(更现实的)缺点是,对于我所展示的幼稚代码,大规模书籍更新可能会慢得多,因为他们会在每次更新时向作者发送ping,以更新他们的数据。这通常通过设置一个标志来暂时禁用调用来解决 update_pub_date

        2
  •  3
  •   Ofri Raviv    16 年前
    from django.db.models import Max
    Author.objects.annotate(max_pub_date=Max('books__pub_date')).order_by('-max_pub_date')
    

    这需要使用django 1.1

        3
  •  1
  •   ayaz    16 年前

    或者,你可以玩这样的游戏:

    Author.objects.filter(book__pub_date__isnull=False).order_by('-book__pub_date')

        4
  •  0
  •   DevDevDev    16 年前
     def remove_duplicates(seq): 
        seen = {}
        result = []
        for item in seq:
            if item in seen: continue
            seen[item] = 1
            result.append(item)
        return result
    
    
    # Get the authors of the most recent books
    query_result = Books.objects.order_by('pub_date').values('author')
    # Strip the keys from the result set and remove duplicate authors
    recent_authors = remove_duplicates(query_result.values())
    
        5
  •  0
  •   Josh Ourisman    16 年前

    在ayaz解决方案的基础上,如何:

    推荐文章