Django复杂的查询集

时间:2014-09-03 19:26:04

标签: django

我想弄清楚如何在没有运气的情况下解决这个问题。情况是作者有很多书籍按类型划分,我希望在查询作者时它会返回作者和书籍对象除以流派。

Author object would have these properties:
    name
    fantasy - would have one book based by given date
    crime   - would have one book based by given date
    romance - would have one book based by given date

通过不在作者模型中制作成千上万的外键(如果我将拥有那么多类型),有没有一种理智的方法来实现这一点?

class Author(models.Model):
    name = models.CharField(u'Name',max_length=100)

GENRE = (
    (0,u'Fantasy'),
    (1,u'Crime'),
    (2,u'Romance')
)

class Book(models.Model):
    author  = models.ForeignKey(Author)
    name    = models.CharField(u'Name',max_length=100)
    genre   = models.SmallIntegerField(u'Genre',choices=GENRE)
    date    = models.DateField(u'Publish date')

编辑:

经过仔细检查后,sgarza62的例子似乎与大量数据有关。 所以我尝试了新的django 1.7功能Prefetch

authors = Author.objects.all().prefetch_related(
        Prefetch("book", queryset=Book.objects.filter(genre=0,date_from__lte=datetime.datetime.now()), to_attr='x_fantasy'),
        Prefetch("book", queryset=Book.objects.filter(genre=1,date_from__lte=datetime.datetime.now()), to_attr='x_crime'),
        Prefetch("book", queryset=Book.objects.filter(genre=2,date_from__lte=datetime.datetime.now()), to_attr='x_romance')
)

但我有2个问题,如何预取一个对象(本例中的最新书),第二个,如何根据预取值进行排序。

1 个答案:

答案 0 :(得分:2)

如果您要查询所有或多位作者,我建议 prefetching related fields 。这将在一次点击中抢夺所有相关对象到数据库,并将对象存储在Queryset中。

authors = Author.objects.all().prefetch_related('book_set')
for author in authors:
    # accessing related field will not cause a hit to the db,
    # because values are cached in Queryset
    for book in author.books_set:
        print book.genre

如果您只是查询一位作者,那么这不是什么大问题。

author = Author.objects.get(pk=1)
her_books = author.book_set
for book in her_books:
    print book.genre

修改

我很难理解你将要做的事情。但是,如果您正在为某位作者寻找每种类型的最新书籍:

author = Author.objects.get(pk=1)
author_books = author.book_set.order_by('-date') # most recent, first
author_genres = set([b.genre for b in author_books])
for g in author_genres:
    print next((b for b in author_books if b.genre==g), None)

请记住,这些操作都在Queryset上,并且每次都没有访问数据库。这很好,因为查询数据库是一项昂贵的操作,并且大多数作者都有相对较小的作品列表,因此查询集通常很小。