【问题标题】:Getting related models from queryset of one-to-many relation with polymorphism从具有多态性的一对多关系的查询集中获取相关模型
【发布时间】:2014-10-23 22:09:16
【问题描述】:

第 1 步:

假设我有两个 one->many 相关的模型,例如:

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 步:

我不确定解决方案是否存在显着差异。

假设现在我有 Book 的 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 中的示例仅显示直接的最小值/最大值。如果我从所有图画书开始,那么我会想念那些没有图画书的作者。 This question 有点相关,但很老。我正在使用 Django 1.7。

【问题讨论】:

    标签: django django-models


    【解决方案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 对象的查询集 arg 您可能会提高效率。

    我将latest_book 设为 Author 的成员以保持示例代码的简洁性,但实际上您可能希望在 Author 模型的定义之外使用它,因为它在调用适当预取的特定实现之外没有用处。

    我不熟悉 django-polymorphic 包,但我打赌您可以使用这种方法来发挥自己的优势,因为预取也支持泛型关系。

    【讨论】:

    • 抱歉 - 我忘记了示例代码中的 ForeignKey。我可以在没有 ManyToMany 的情况下使用预取的东西吗?另外我必须说,将所有书籍加载到内存中可能不是一种选择:-(。
    • 哦,我误读了它是一对多的。这让事情变得容易多了。使用 ForeignKey,您可以简单地选择执行 SQL JOIN 的 select_related('books')。
    • select_related 似乎适用于多对一方向:Book.objects.select_related("author"),但反过来对我不起作用。 Author.objects.select_related("book") -> 运行,但 Author 对象上没有属性 book。
    • 您需要在 ForiegnKey 上设置related_name kwarg 或使用默认的相关名称:Author.objects.select_related('book_set')
    • 是的,选择相关作品。 (后来使用 author.book_set.get_queryset()... )。但我想它仍然存在将所有内容加载到内存中的问题。
    猜你喜欢
    • 1970-01-01
    • 2017-08-12
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-06
    • 2019-07-29
    • 1970-01-01
    相关资源
    最近更新 更多