django orm - 如何在其父类(super class)的子类的外键上使用 select_related()

标签 django inheritance orm

我一直发现 Django orm 对子类模型的处理非常漂亮。这可能就是我遇到这样的问题的原因。

取三个模型:

class A(models.Model):
    field1 = models.CharField(max_length=255)

class B(A):
    fk_field = models.ForeignKey('C')

class C(models.Model):
    field2 = models.CharField(max_length=255)

所以现在你可以查询 A模型并获得所有 B型号,如果可用:
the_as = A.objects.all()
for a in the_as:
    print a.b.fk_field.field2 #Note that this throws an error if there is no B record

这样做的问题是您正在查看大量数据库调用来检索所有数据。

现在假设您想检索所有 A 的 QuerySet。数据库中的模型,但使用所有子类记录和子类的外键记录,使用 select_related()将您的应用程序限制为单个数据库调用。你会写一个这样的查询:
the_as = A.objects.select_related("b", "b__fk_field").all()

一个查询返回所有需要的数据!惊人的。

除了没有。因为这个版本的查询正在做自己的过滤,即使 select_related根本不应该过滤任何结果:
set_1 = A.objects.select_related("b", "b__fk_field").all() #Only returns A objects with associated B objects
set_2 = A.objects.all() #Returns all A objects
len(set_1) > len(set_2) #Will always be False

我使用 django-debug-toolbar 来检查查询并发现问题。生成的 SQL 查询使用 INNER JOIN加入C查询的表,而不是 LEFT OUTER JOIN像其他子类字段一样:
SELECT "app_a"."field1", "app_b"."fk_field_id", "app_c"."field2"
FROM "app_a" 
    LEFT OUTER JOIN "app_b" ON ("app_a"."id" = "app_b"."a_ptr_id") 
    INNER JOIN "app_c" ON ("app_b"."fk_field_id" = "app_c"."id");

看来如果我只是更改 INNER JOINLEFT OUTER JOIN ,然后我得到了我想要的记录,但是在使用 Django 的 ORM 时这对我没有帮助。

这是 select_related() 中的错误吗?在 Django 的 ORM 中?是否有任何解决方法,或者我是否只需要直接查询数据库并自己映射结果?我应该使用像 Django-Polymorphic 这样的东西来做到这一点吗?

最佳答案

它看起来像一个错误,特别是它似乎忽略了 A->B 关系的可为空性质,例如,如果您在 A 中有一个对 B 的外键引用而不是子类化,那么该外键当然可以为空并且django 会使用左连接。您可能应该在 django 问题跟踪器中提出这个问题。您也可以尝试使用 prefetch_related 而不是 select_related 来解决您的问题。

关于django orm - 如何在其父类(super class)的子类的外键上使用 select_related(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11020813/

相关文章:

javascript - jQuery,AJAX 使用 JSON 发布 Javascript 数组

python - 如何在 Django 1.1 中执行 "Group By"查询?

javascript - django tinymce javascript 未在非管理页面上加载

c# - C#实现继承的正确方法

php - 如何在 Laravel 4 中创建 Hstore 列类型?

Django ORM,排除两个值

Django 操作错误 : could not fork new process for connection

C++ 函数指针参数和类继承自动转换

java - Hibernate 继承映射未知属性

django - 通过反向外键关系过滤使用存在的元素