13

我在这里阅读了文档和所有相关问题,但我没有正确理解select_related在链式/多个外键上的行为方式。

假设我们有以下模型:

class RecordLabel(models.Model):
   title = models.CharField(...)

class Band(models.Model):
   band_name = models.CharField(...)

class Artist(models.Model):
   record_label = models.ForeignKey(RecordLabel,...)
   belongs_to_band = models.ForeignKey(Band, ...)

class Producer(models.Model):
   customer = models.ForeignKey(Artist, ...)

A.我们如何使用 select_related 在

Producer.objects.filter(...).select_related(?)

查询以便预加载所有内容?会不会是这样:

Producer.objects.filter(...).select_related(
    'customer__record_label', 'customer__belongs_to_band')

为什么?

B.如果类 Band 有 'Genre' 作为外键,

 class Genre(models.Model):
       genre_name = models.CharField(...)        

 class Band(models.Model):
       band_name = models.CharField(...)
       music_genre = models.ForeignKey(Genres, ...)

然后为了预先加载所有内容,我们将执行以下操作:

Producer.objects.filter(...).select_related(
    'customer__record_label__music_genre', 'customer__record_label__band_name',
    'customer__belongs_to_band__music_genre', 'customer__belongs_to_band__music_genre') 

或类似的东西:

Producer.objects.filter(...).select_related(
    'customer__record_label__music_genre', 'customer__record_label__band_name',
    'customer__belongs_to_band', 'customer__belongs_to_band') 
4

2 回答 2

11

关于问题B:

如果我正确理解您的问题,您只需指定一次字段,无需重复。

注意:我在这里再次显示您的模型的最终版本,否则我会感到困惑。

class RecordLabel(models.Model):
    title = models.CharField(...)

class Genre(models.Model):
    genre_name = models.CharField(...)

class Band(models.Model):
    band_name = models.CharField(...)
    music_genre = models.ForeignKey(Genre, ...)

class Artist(models.Model):
    record_label = models.ForeignKey(RecordLabel, ...)
    belongs_to_band = models.ForeignKey(Band, ...)

class Producer(models.Model):
    customer = models.ForeignKey(Artist, ...)

选择所有相关模型(进行一个大连接 SQL 查询):

qs = Producer.objects.filter(...).select_related(
    'customer__record_label',
    'customer__belongs_to_band__music_genre')

第一部分 ( customer) 预取相关艺术家和相关唱片公司 ( __record_label);第二部分不需要获取艺术家,因为它已经存在,但它会继续预获取相关的乐队 ( __belongs_to_band),然后是相关的流派 ( __music_genre)。现在您有一个访问所有 5 个表(模型)的 SQL 查询。

提示:您可以使用qs.query来查看您的查询将生成的 SQL 语句的基本概念;这应该让您了解它所做的连接。

如果您在查询时遇到问题,那么您应该添加更多关于到底发生了什么以及您期望什么的信息。

于 2018-09-19T17:03:33.370 回答
1

对于问题 A: 将参数作为字符串传递

qs = Producer.objects.filter(...).select_related(
    'customer__record_label', 'customer__belongs_to_band')

编辑:似乎缺少的引号只是提问者的错字,而不是真正的问题。

于 2018-09-19T16:34:40.387 回答