2014-08-29 38 views
0

第1步:獲取相關的從一到多的關係queryset的機型多態性

假設我有兩個一>許多相關型號如:

from django.db import models 
class Author(models.Model): 
    name = models.CharField(max_length=100) 

class Book(models.Model): 
    name = models.CharField(max_length=300) 
    author = models.ForeignKey(Author) 
    pubdate = models.DateField() 

我怎樣才能得到所有作者的名單和他們上一本書的名稱(或者說書本身)?

  • 沒有每篇文章一個查詢
  • 有些作者可能尚未出版了一本書,我還是希望他們在列表(無)
  • 對於可移植性我想避免手動SQL
  • 它不應該加載所有書籍在內存

第2步:

我不確定這是否是解決方案中的重大差異。

現在假設我有本書的PictureBook子類(使用django-polymorphic),我想知道所有作者的最後PictureBook的picture_url(如果不是,則再次爲None)。

from polymorphic import PolymorphicModel 
class Book(PolymorphicModel): 
    name = models.CharField(max_length=300) 
    author = models.ForeignKey(Author) 
    pubdate = models.DateField() 

class PictureBook(Book): 
    picture_url = models.CharField(max_length=200) 

不幸的是,documentation about annotate中的示例僅顯示直接的最小/最大值。如果我從所有PictureBook開始,那麼我會想念那些沒有的作者。 This question與somwhat有關,但非常古老。我正在使用Django 1.7。

回答

1

在你的第一個例子,如果這種關係被建立,如:

from django.db import models 
class Author(models.Model): 
    name = models.CharField(max_length=100) 
    books = models.ManyToMany(Book) 

    def latest_book(self): 
     """ 
     This is only efficient/accurate if you've prefetched books 
     in the right order! 
     """ 
     if self.books.exists(): 
      return self.books.all()[0] 
     return None 


class Book(models.Model): 
    name = models.CharField(max_length=300) 
    pubdate = models.DateField() 
在1.7推出的 Prefetch對象

然後:

from django.db.models import Prefetch 
authors = Author.objects.all().prefetch_related(
    Prefetch('books', queryset=Books.objects.order_by('-pubdate') 

for author in authors: 
    print author.latest_book() 

2數據庫查詢,當然要注意你正在爲每個作者加載每本書到記憶中。也就是說,使用Prefetch對象的queryset arg,你可能會使這個效率更高。我發現latest_book是作者的一個成員,它使示例代碼保持輕量級,但實際上,您可能希望在Author模型的定義之外,因爲在此特定實現之外,在調用適當的預取的情況下它沒有用。

我對django-polymorphic軟件包並不熟悉,但我敢打賭,您可以使用這種方法來獲得優勢,因爲預取也支持泛型關係。

+0

對不起 - 我在示例代碼中忘記了ForeignKey。在沒有ManyToMany的情況下我可以使用prefetch嗎?另外我必須說,在內存中加載所有的圖書可能不是一個選項:-(。 – Zulan 2014-08-29 22:45:41

+0

噢,我誤解它是一對多的,這使得事情變得更容易。使用ForeignKey,你可以簡單地選擇相關('書籍')執行一個SQL JOIN。 – 2014-08-29 23:17:25

+0

'select_related'似乎適用於多對一的方向:'Book.objects.select_related(「author」)',但反過來也不適用於我'。Author.objects .select_related(「book」)' - >運行,但Author對象上沒有屬性簿。 – Zulan 2014-08-30 08:44:50