首页 > 解决方案 > 在 Django 的 ORM 中只使用 `foreign_key=` 和 `foreign_key_id=` 有什么区别吗?

问题描述

以下之间似乎没有区别:

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

打印出 Django 为这两种情况生成的 SQL 表明它是相同的。但是,我无法在任何地方找到此正式文档,因此我担心在某些情况下使用 justmodelb可能会导致与modelb_id.

我特别感兴趣的是有人将我指向确认这些东西是等效的官方消息来源。

标签: pythonsqldjangoorm

解决方案


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

数据库表示

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

模型字段子类django.db.models.fields.Field。该类Field有一个attname字段,该字段在源代码内部记录为解析要在模型对象上使用的属性的方式。

# 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)

作为为编译的 SQL 查询转换 kwargs 中的QuerySet.filter名称的执行流程的一部分,名称被转换为PathInfo包含相应名称的模型字段的元组。

在第 1354django.db.models.sql.query.Query行,是以下行:

field = opts.get_field(name)

Nowopts是一个实例,django.db.models.options.Options方法get_field委托给_forward_fields_mapfields_map缓存的属性。

当您查看这两个属性的实现时,您会看到它们返回一个字典映射field.nametofieldfield.attnameto field

这使得它modelb_id可以modelb从任一缓存属性解析为模型字段。

在我看来,这并不重要,modelb_id或者modelb作为关键字参数传递给QuerySet.filter. 只有前一个关键字需要了解实现细节。

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


推荐阅读