这是我经常遇到的问题。假设我有三个模型:
class CourseType(models.Model):
name = models.CharField(max_length=50)
class CourseLevel(models.Model):
name = models.CharField(max_length=50)
course_type = models.ForeignKey(CourseType, on_delete=models.CASCADE)
class Course(models.Model):
name = models.CharField(max_length=50)
course_level = models.ForeignKey(CourseLevel, on_delete=models.CASCADE)
def __str__(self):
return "{}-{}: {}".format(self.course_level.course_type.name, self.course_level.name, self.name)
如果我要遍历Course.objects.all()
并打印Course
对象,那将是一个 n+1 查询。这很容易通过使用解决select_related
:
Course.objects.select_related('course_level', 'course_level__course_type')
问题是我必须记住select_related
每次都使用。它也很丑陋,尤其是如果您在那里有另一个模型,例如CourseDetails
.
一种解决方案是使用自定义管理器:
class CourseManager(models.Manager):
def with_names(self):
return self.select_related('course_level', 'course_level__course_type')
然后我可以使用Course.with_names.all()
,不再需要select_related
每次都添加。这有一个主要限制 - 我只能在直接使用Course
. 很多时候我会通过外键迭代Course
对象,并且我需要再次记住select_related
在我的代码中使用和乱扔它。一个例子:
class Student(models.Model):
name = models.CharField(max_length=50)
class StudentCourseEnroll(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
现在如果我想打印所有学生和他们注册的课程,我必须再次记住使用select_related
它甚至更丑:
StudentCourseEnroll.objects.select_related('course__course_level__course_type', 'course__course_level')
我可以创建另一个经理,StudentCourseEnroll
但这似乎违背了 DRY 原则——我会让多个经理做同样的事情。
有没有更好的方法来解决这个问题?我可以直接在Course
模型中做些什么来避免考虑这个问题吗?