说我有这样的模特。
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吗?
我查看了一下源代码,但无法找到问题的答案
答案 0 :(得分:9)
您可能正在谈论的是client
和client_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