在Django的ORM中仅使用`foreign_key =`与`foreign_key_id =`之间有什么区别吗?

时间:2018-11-10 00:57:27

标签: python sql django orm

以下内容似乎没有区别:

ModelA.objects.filter(modelb_id=a_model_id)
ModelA.objects.filter(modelb=a_model_id)

打印出两种情况下Django生成的SQL都表明它是相同的。但是,我在任何地方都找不到官方记录的文档,因此,我担心在某些情况下仅使用modelb可能会导致与modelb_id有所不同。

我特别感兴趣的是有人向我指出可以确认这些内容相同的官方消息。

1 个答案:

答案 0 :(得分:2)

TLDR:最好考虑框架作者的建议并使用模型字段名称。

  

数据库表示形式

     

在后台,Django将“ _id”附加到字段名称以创建其数据库列名称。在上面的示例中,Car模型的数据库表将具有一个制造商ID列。 (您可以通过指定db_column显式更改此设置。)但是,除非编写自定义SQL,否则您的代码永远不必处理数据库列名。您将始终处理模型对象的字段名称。 Reference

模型字段子类django.db.models.fields.FieldField类具有一个attname字段,该字段是documented internally in the source code,用于解析要在模型对象上使用的属性。

# A guide to Field parameters:
#
#   * name:      The name of the field specified in the model.
#   * attname:   The attribute to use on the model object. This is the same as
#                "name", except in the case of ForeignKeys, where "_id" is
#                appended.
#   * db_column: The db_column specified in the model (or None).
#   * column:    The database column for this field. This is the same as
#                "attname", except if db_column is specified.
#
# Code that introspects values, or does other dynamic things, should use
# attname. For example, this gets the primary key value of object "obj":
#
#     getattr(obj, opts.pk.attname)

作为执行converting the QuerySet.filter names in the kwargs for the compiled SQL query的一部分,将名称转换为包含相应名称的模型字段的PathInfo元组。

On Line 1354 for django.db.models.sql.query.Query,是以下行:

field = opts.get_field(name)

现在optsdjango.db.models.options.Options的实例,并且get_field方法委托给_forward_fields_mapfields_map缓存的属性。

当您查看这两个属性的实现时,您会看到它们返回从field.namefieldfield.attnamefield的字典映射。

这使得modelb_idmodelb从任一缓存的属性解析为模型字段。

我认为,将modelb_idmodelb作为关键字参数传递给QuerySet.filter并不重要。只有前一个关键字需要了解实现细节。

但是最好考虑框架作者的建议并使用模型字段名称。