问题
Suppose I have the following in my models.py:
class Book:
pass
class Part:
book = models.ForeignKey(Book)
class Chapter:
part = models.ForeignKey(Part)
number = models.IntegerField()
I would like to do
book = Book.objects.get(id=someID)
chapters = Book.chapters.get(number=4)
What is a clean way to do so? I thought of a Manager on the book class but it doest not seem to work for this case.
Of course I could implement a method get_chapters on class book but i would like to avoid this.
any ideas ?
回答1:
Using related_name arguments for FK fields, coupled with prefetch_related for a queryset, will allow you to fetch all info related to a book with minimal performance hit (each prefetch_related param calls a separate query).
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()
You can do this in a template as well.
However, for the most performant solution, save a FK to book from chapter as well. This can be easily done by overriding the save method.
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())
来源:https://stackoverflow.com/questions/37515302/django-shortcut-nested-foreign-key