繁体   English   中英

如何使用 django ORM 在外键字段上连接两个表?

[英]How do you join two tables on a foreign key field using django ORM?

假设我有以下模型:

class Position(models.Model):
    name = models.CharField()

class PositionStats(models.Model):
    position = models.ForeignKey(Position)
    averageYards = models.CharField()
    averageCatches = models.CharField()

class PlayerStats(models.Model):
    player = models.ForeignKey(Player)
    averageYards = models.CharField()
    averageCatches = models.CharField()

class Player(models.Model):
    name = models.CharField()
    position = models.ForeignKey(Position)

我想使用 django 的 ORM 执行等效的 SQL 查询:

SELECT *

FROM PlayerStats

JOIN Player ON player

JOIN PositionStats ON PositionStats.position = Player.position

我将如何使用 django 的 ORM 做到这一点? 查询并不完全正确,但我的想法是我想要一个使用 django 的 ORM 的查询,它让我根据玩家的位置将PlayerStatsPositionStats连接起来。

我已经和 django 一起工作了一段时间,我在弄清楚表格连接方面遇到了相当困难的时间,但我想我终于明白了,我想把它传递给其他人,这样他们就可以避免我的挫败感用它。

考虑以下model.py:

class EventsMeetinglocation(models.Model):
    id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=200)

    class Meta:
        managed = True
        db_table = 'events_meetinglocation'

class EventsBoardmeeting(models.Model):
    id = models.IntegerField(primary_key=True)
    date = models.DateTimeField()
    agenda_id = models.IntegerField(blank=True, null=True)
    location_id = models.ForeignKey(EventsMeetinglocation)
    minutes_id = models.IntegerField(blank=True, null=True)

    class Meta:
       managed = True
       db_table = 'events_boardmeeting'

在这里,我们可以看到, location_idEventsBoardmeeting是在ID的外键EventsMeetinglocation 这意味着我们应该能够通过EventsBoardmeeting查询EventsMeetinglocation的信息。

现在考虑以下views.py:

def meetings(request):
    meetingData = EventsBoardmeeting.objects.all()
    return render(request, 'board/meetings.html', {'data': meetingData })

正如之前在其他帖子中多次提到的,django 会自动处理连接。 当我们在EventsBoardmeeting查询所有内容时,我们也会通过外键获取任何相关信息,但是我们在 html 中访问它的方式有点不同。 我们必须通过用作外键的变量来访问与该连接关联的信息。 例如:

{% for x in data %}
   {{ x.location_id.name }}
{% endfor %}

以上引用了表中作为外键连接结果的所有名称。 x本质上是EventsBoardmeeting表,因此当我们访问x.location_id我们正在访问外键,这使我们可以访问EventsMeetinglocation的信息。

这不是一个查询,但它非常有效。 这对涉及的每个表执行一次查询,并在 Python 中连接它们。 更多关于prefetch_related在这里: https : //docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related

Player.objects.filter(name="Bob").prefetch_related(
        'position__positionstats_set', 'playerstats_set')

select_related()prefetch_related()是您的解决方案。 它们的工作方式几乎相同,但有一些不同。

select_related()通过创建 SQL 连接并在 SELECT 语句中包含相关对象的字段来工作。 为此, select_related获取同一数据库查询中的相关对象。 但它只适用于一对一或一对多的关系。 示例如下-

entry = Entry.objects.select_related('blog').get(id=5)
or
entries = Entry.objects.filter(foo='bar').select_related('blog')

另一方面, prefetch_related()对每个关系进行单独的查找,并在 Python 中进行“连接”。 这允许它预取多对多和多对一对象,这是使用select_related无法完成的。 因此prefetch_related将对每个关系只执行一个查询。 示例如下-

Pizza.objects.all().prefetch_related('toppings')

在 Django 3.2 中,框架在使用方法 QuerySet.filter() 时会自动遵循关系

# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(question__pub_date__year=current_year)

这将编译为以下 SQL 查询:

SELECT
    "polls_choice"."id",
    "polls_choice"."question_id",
    "polls_choice"."choice_text",
    "polls_choice"."votes"
FROM
    "polls_choice"
INNER JOIN "polls_question" ON
    ("polls_choice"."question_id" = "polls_question"."id")
WHERE
    "polls_question"."pub_date" BETWEEN 2020-12-31 23:00:00 AND 2021-12-31 22:59:59.999999

请参阅此处的教程: https : //docs.djangoproject.com/en/3.2/intro/tutorial02/

django.db导入连接在您的视图中包含以下语句:

cursor = connection.cursor()
cursor.execute("select * From Postion ON Position.name = Player.position JOIN
PlayerStats ON Player.name = 
PlayerStats.player JOIN PositionStats ON Position.name = PositionStats.player")
solution = cursor.fetchall()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM