Django 升级 filter/prefetch_related 行为改变?

Django upgrade filter/prefetch_related behaviour change?

我正在从 Django 1.8.19 升级到 1.11.15,我发现了一段有问题的代码。

特别是此查询正在执行与之前不同的操作。

project_groups = brand.project_groups.prefetch_related(
   'project', 'project__score', 'project__themes').filter(
   project=projects
).distinct()

之前(在 Django 1.8 中),根据 "project_groups.query" 的输出,它产生了 SQL 包括:

... projectgroup.project_id IN [projects query]

现在它产生 SQL 读数:

... projectgroup.project_id = [projects query]

这中断为 [projects query] returns 不止一行。所以我得到一个:

ProgrammingError: more than one row returned by a subquery used as an expression

我对这次升级的代码所做的唯一更改是模型和迁移,以使用 django.contrib.postgres.fields 中的 ArrayField 和 HStoreField 而不是 django_hstore 等价物。

我的猜测是原来的代码是错误的,但由于 Django (filter/prefetch_related) 中的一个错误现在已经修复。这可能是正确的吗?如果这实际上是 Django 中的 new 错误,我不想编写依赖于它的代码!

Django 的字段查找行为在 1.8 和 1.9 之间发生了变化,解释了这一点 - 您可以在 Django ticket #25284 上查看详细信息。

在 Django 1.8 中,诸如 Model.objects.filter(related_id = RelatedModel.objects.all()) 的查询用于导致隐式 __in 查找,因此 SQL 查询包含 related_id IN (SELECT id FROM ...)。但在 Django 1.9 中,"IN" 更改为“=”,这会导致查询在 MySql 和 Postgres 中中断。由于隐式 "IN" 行为未记录且可能是偶然的,因此该更改被归类为错误修复。

您应该能够通过向字段查找添加显式查找类型(例如 .filter(project__in=projects) - 参见 Django Documentation: Field Lookups

来相当轻松地修复查询