Django - 跟踪外键关系(即 SQL 中的 JOIN)

2 投票
2 回答
4595 浏览
提问于 2025-04-15 13:23

我最近在玩 Django,但有一件事让我有点困惑,那就是如何处理外键关系。其实我在写 SQL 方面有很多经验,所以如果没有 ORM(对象关系映射),我可能能直接得到结果。

简单来说,我想要的 SQL 查询是这样的:

Select
  table1.id
  table1.text
  table1.user
  table2.user_name
  table2.url
from table1, table2
where table1.user_id = table2.id

我的模型类已经定义好了:

class Table1(models.Model):
    #other fields
    text        = models.TextField()
    user        = models.ForeignKey('table2')

class Table2(models.Model):
    # other fields
    user_name = models.CharField(max_length=50)
    url = models.URLField(blank=True, null=True)

我已经查看了 Django 网站上的文档,了解了查询集、模型和视图的内容。但我还是不太清楚该怎么做。

我还设置了一个通用的列表视图的 URL,但我想在模板中访问第二个表的 user_name 字段。我在 urls.py 中尝试了 select_related,也在命令行中试过,但似乎都不管用。下面是一些例子。

在 urls 中的配置:

url(r'^$','django.views.generic.list_detail.object_list', { 'queryset': Table1.objects.select_related() }),

在命令行中:

>>> a = Table1.objects.select_related().get(id=1)
>>> a.id
1
>>> a.user_name
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'Table1' object has no attribute 'user_name'

所以,基本上,

  • 我哪里做错了?
  • 我是不是漏掉了什么?
  • 在同一个查询集中,如何将两个表的字段传递到模板中(这样就可以访问两个表的字段)?
  • 这可以用通用视图来实现吗?

2 个回答

2

select_related() 并不是直接把第二个表的数据加到查询里,它只是“加载”了这些数据,而不是懒懒地给你。你只有在确定它能提升你网站性能的时候才应该使用它。要获取第二个表的数据,你需要写

a.user.username

在 Django 中,要获取相关的表,你需要通过你设计的外键来跟踪它们。查询本身并不会直接转换成 SQL 查询,因为它是“懒惰”的。它只会在你需要的时候,执行你需要的 SQL。

如果你使用了 select_related,那么在你对 a 进行原始查询时,SQL 就会被执行。但如果你没有使用 select_related,那么数据库只会在你实际执行 a.user.username 时才会加载数据。

4

像这样应该可以工作:

u = Table1.objects.get(id=1)
print u.id
print u.user.user_name

如果你想要使用外键(就是表与表之间的关联),你必须明确地去做。也就是说,当你从表1获取一个对象时,并不会自动连接到表2。只有当你访问外键字段时,比如这个例子中的用户,才会得到表2中的对象。

撰写回答