Django 快捷方式嵌套外键

v.t*_*rey 4 python django nested foreign-key-relationship

假设我的 models.py 中有以下内容:

class Book:
    pass

class Part:
    book = models.ForeignKey(Book)

class Chapter:
    part = models.ForeignKey(Part)
    number = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

我想要做

book = Book.objects.get(id=someID)
chapters = Book.chapters.get(number=4)
Run Code Online (Sandbox Code Playgroud)

什么是干净的方法?我在书本课上想到了经理,但它似乎不适用于这种情况。

当然,我可以在课堂书籍上实现 get_chapters 方法,但我想避免这种情况。

有任何想法吗 ?

Ian*_*ice 6

使用 FK 字段的 related_name 参数,再加上查询集的 prefetch_lated,将允许您以最小的性能影响获取与书籍相关的所有信息(每个 prefetch_lated 参数调用一个单独的查询)。

class Book:
    pass

class Part:
    book = models.ForeignKey(Book, related_name="parts")

class Chapter:
    part = models.ForeignKey(Part, related_name="chapters")
    number = models.IntegerField()

# fetch a book and all related info w/ only 2 db hits
book = Book.objects.first().prefetch_related("parts","parts__chapters")
print(book.parts.all()) # returns all parts for book
for part in book.parts.all():
    print part.chapters.all()
Run Code Online (Sandbox Code Playgroud)

您也可以在模板中执行此操作。

但是,为了获得最佳性能的解决方案,请同时保存 FK 以从章节中进行预订。这可以通过重写 save 方法轻松完成。

class Chapter:
    part = models.ForeignKey(Part, related_name="part_chapters")
    number = models.IntegerField()
    book = models.ForeignKey(Book, related_name="chapters", null=True, blank=True) # allow null/blank values; will be populated in save method
    def save(self, *args, **kwargs):
        self.book = self.part.book
        super(Chapter, self).save(*args, **kwargs)

>>> book = Book.objects.first().prefetch_related("parts","chapters")
>>> print(book.parts.all()) # returns all parts for book
>>> print(book.chapters.all())
Run Code Online (Sandbox Code Playgroud)