复杂的Django自引用注解
这里有两个模型:
Floor
(楼层),它有一个指向自己的引用,叫做previousFloor
,对于第一个Floor
来说,这个值可以是null
。Room
(房间),当然只能在一个Floor
上(但一个Floor
上可以有多个房间)。
我需要一个查询,返回所有在顶层的房间。
为了实现这个目标,我在 Floor
模型中创建了一个叫 get_next_floor
的函数,它会返回与当前楼层相连的下一个楼层,如果没有下一个楼层(也就是最后一个楼层),就返回 None
。还有一个函数叫 is_last_floor
,如果 get_next_floor
返回 None
,它就返回 True
,否则返回 False
。
最后,我会遍历所有的房间,并对每个房间所在的 Floor
调用 is_last_floor
,以判断它是否符合我的条件。
这个问题可以通过在循环中保存已经找到的最后一个 Floor
来稍微优化一下。
不过,由于这只是我实际问题的一个抽象,而且我在处理一个大型数据库,这种方法因为循环的性能太差,已经不再可行。
有没有办法用一个查询和注解来实现这个?
1 个回答
1
一个楼层,如果是最高的那个Floor
,那么肯定是没有其他的Floor
把它当作previousFloor
来引用。
所以:
top_floors = Floor.objects.exclude(id__in=Floor.objects.filter(previous_floor__isnull=False).values_list('previous_floor', flat=True))
这可以理解为:
SELECT "core_floor"."id", "core_floor"."name", "core_floor"."previous_floor_id" FROM "core_floor" WHERE NOT ("core_floor"."id" IN (SELECT U0."previous_floor_id" FROM "core_floor" U0 WHERE U0."previous_floor_id" IS NOT NULL))
不过,MySQL在处理嵌套查询时表现不是很好,所以可能更有效的方法是:
lower_floors = Floor.objects.filter(previous_floor__isnull=False).values_list('previous_floor', flat=True)
top_floors = Floor.objects.exclude(id__in=list(covered_floors))
可以查看这个链接了解更多信息:https://docs.djangoproject.com/en/dev/ref/models/querysets/#in
然后要获取顶层的房间:
Room.objects.filter(floor__in=top_floors)