【发布时间】:2012-06-13 18:09:40
【问题描述】:
我一直发现 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 JOIN 更改为LEFT OUTER JOIN,那么我会得到我想要的记录,但这在使用 Django 的 ORM 时对我没有帮助。
这是 Django 的 ORM 中 select_related() 中的错误吗?有什么解决方法,还是我只需要直接查询数据库并自己映射结果?我应该使用 Django-Polymorphic 之类的东西来做到这一点吗?
【问题讨论】:
标签: django inheritance orm