如何使用带有 WHERE 子句的 Django ORM 连接三个表

Lju*_*vac 7 django django-models django-orm

我有三个模型:

class model_A(models.Model):
    data_1 = models.CharField(max_length=60)
    data_2 = models.SmallIntegerField()
    data_3 = models.IntegerField(blank=True, null=True)

class model_B(models.Model):
    data_a = models.ForeignKey(model_A)
    data_1 = models.CharField(max_length=5)
    data_2 = models.IntegerField()

class model_C(models.Model):
    data_a = models.ForeignKey(model_A)
    data_1 = models.CharField(max_length=5)
    data_2 = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

所以你可以看到有间的一种一对一关系model_B ? model_Amodel_C ? model_A,这是非常简单的。

我需要使用 WHERE 子句对这三个表进行 JOIN,因此使用 RAW SQL 将是:

SELECT * FROM `model_A` JOIN `model_B` ON `model_A`.`data_1` = `model_B`.`data_a` JOIN `model_C` ON `model_A`.`data_1` = `model_C`.`data_a` WHERE `model_B`.`data_1` = 1 AND `model_C`.`data_1` = 1
Run Code Online (Sandbox Code Playgroud)

如何filter使用 Django ORM对这三个表进行 JOIN(使用语句(WHERE 子句))?

可能重复? 有人链接的重复问题已加入两个表,使用 select_related() 很容易解决。但是它对三个表不起作用(或者我不知道在这种情况下如何使用它)。

Mel*_*vyn 6

当然,这并不是一个好的模型定义,所以让我们先解决这个问题:

from django.db import models

class Artist(models.Model):
    name = models.CharField(max_length=60)
    year_established = models.SmallIntegerField()
    votes = models.IntegerField(blank=True, null=True)


class Song(models.Model):
    artist = models.ForeignKey(Artist, related_name='songs')
    title = models.CharField(max_length=5)
    votes = models.IntegerField()


class Fan(models.Model):
    artist = models.ForeignKey(Artist, related_name='fans')
    name = models.CharField(max_length=5)
    votes_casted = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

现在让我们让所有写过关于爱情的歌曲并且拥有至少投过 100 票的粉丝的艺术家:

queryset = Artist.objects.select_related(
    'songs', 'fans'
).filter(songs__title__icontains='love', fans__votes_casted__gte=100)
Run Code Online (Sandbox Code Playgroud)

请注意,select_related它在查询中没有作用:它是在迭代集合时最小化查询的优化。

进一步阅读:

编辑:添加了 select_related。这在理论上应该有效并减少查询,但如果没有,我明天会研究它。

  • 我终于成功做到了!`queryset = Artist.objects.prefetch_lated('songs','fans').filter(songs__title__icontains='love', Fans__votes_casted__gte=100` 做到了!我现在可以访问模板中的每个字段(只需访问一次数据库)例如“{{artist.songs.all.0.title }}”。您帮了我很多,所以如果您首先编辑您的答案并进行此更正,我愿意接受您的建议。 (2认同)