Django外键访问如何工作

时间:2014-07-22 15:54:31

标签: python django python-2.7 django-models

说我有这样的模特。

class Job(models.Model):
    client = models.ForeignKey(Contacts, null=True)

并且假设我有工作j。我知道我可以像这样访问属于j的客户端

 j.client

但也有

 j.client_id

所以我的问题是如何访问j.client工作?

django存储client__id然后当调用j.client时它会查询找到正确的对象吗?

或是对象引用存储到j并且访问client__id是从Contact对象获取id吗?

我查看了一下源代码,但无法找到问题的答案

3 个答案:

答案 0 :(得分:9)

您可能正在谈论的是clientclient_id(单个下划线)。

client_id属性是常规(整数)属性。这是保存到数据库的外键。即使您将client_id指定为ForeignKey,您也只会在数据库中看到client列。

client属性是对象描述符实例。这是一个覆盖__get____set__方法的特殊类,因此设置和访问该属性会调用该类的方法。这是让您访问实际相关模型实例的神奇之处。 __get__将根据client_id属性从数据库中检索正确的模型实例(如果尚未加载)。 __set__还会将client_id属性设置为相关对象的主键,以便client_id始终保持最新状态。

请注意,此属性在查询查找中也可用,非常方便。例如,如果您只有外来对象的主键,而不是模型实例本身,则以下查询看起来非常相似:

job = Job.objects.filter(client__id=pk)
job = Job.objects.filter(client_id=pk)

但是,在第一个查询下面访问相关对象的属性(双下划线)并执行OUTER JOIN。第二个查询只访问本地属性,因此不必执行OUTER JOIN语句并保存性能。

答案 1 :(得分:8)

这在文档中解释:
https://docs.djangoproject.com/en/dev/ref/models/fields/#database-representation

在数据库中只有client_id字段(单个下划线)

在模型实例上,您将拥有client属性,当您访问它时,这将导致Django从数据库加载相关对象并实例化为另一个模型实例。

您还将拥有client_id属性(一个下划线),该属性具有相关对象的主键值,存储在db字段中。

在进行ORM查询时,您可以使用client__id(双下划线)语法查找相关模型上的字段,例如,如果client__name模型具有Client模型,您也可以执行name Job.objects.get(client__id=1) Job.objects.filter(client__name='John') client = Client.objects.get(pk=1) Job.objects.get(client=client) 字段。这将成为两个模型的SQL JOIN查询。

例如

{{1}}

答案 2 :(得分:2)

j.client为您提供models.Model个对象。您可以访问它的属性,如...

client = j.client

id = client.id
name = client.name

但是不应该有j.client__id字段。您应该使用j.client.id获取id字段。虽然您可以使用j.client__id字段来执行过滤等。

所以,

id = j.client.id # good
id = j.client__id # bad

job = Job.objects.get(client__id=1) # good
job = Job.objects.get(client.id=1) # bad