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

时间:2009-11-07 07:32:22

标签: python sql database django django-models

考虑模型:

class Author(models.Model):
    name = models.CharField(max_length=200, unique=True)

class Book(models.Model):
    pub_date = models.DateTimeField()
    author = models.ForeignKey(Author)

现在假设我想通过他们的pub_date订购所有书籍。我会用order_by('pub_date')。但是,如果我想要根据最近出版的书籍订购的所有作者的列表怎么办?

当你想到它时,它真的很简单。它基本上是:

  • 最佳作者是最近出版一本书的作者
  • 下一个是出版的书不像第一个那样新的
  • 等等。

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

帮助表示赞赏!

编辑:最后,是否可以选择只为每个字段添加一个新字段以显示上一本书的日期,只是更新整个时间更好?

5 个答案:

答案 0 :(得分:1)

或者,你可以玩这样的东西:

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

答案 1 :(得分:1)

from django.db.models import Max
Author.objects.annotate(max_pub_date=Max('books__pub_date')).order_by('-max_pub_date')

这要求你使用django 1.1

我假设您将在Book模型中向作者字段添加'related_name',因此它将由Author.books而不是Author.book_set调用。它更具可读性。

答案 2 :(得分:1)

  

最后,是否可以选择只添加一个新字段来显示最后一本书的日期,只是更新整个时间更好?

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

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端并删除重复项

这两个选项都选择在读取时从标准化数据计算pub_dates。非规范化在您编写新数据时为每个作者执行此计算。这个想法是大多数网络应用程序读取的次数最多,而不是写入,所以这种方法更可取。

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

另一个(更现实的)缺点是,我已经展示了大量书籍的天真代码更新可能会慢一些,因为他们会ping作者,无论如何更新每次更新的数据。这通常通过使用一个标志暂时禁用调用update_pub_date并在之后手动调用它来解决。基本上,非规范化数据需要比标准化更多的维护。

答案 3 :(得分:0)

 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())

答案 4 :(得分:0)

在ayaz的解决方案的基础上,如何:     Author.objects.filter(book__pub_date__isnull =假).distinct()ORDER_BY( ' - book__pub_date')。