我按以下方式设置Django模型:
模型A与模型B具有一对多的关系
A中的每条记录在B
中有3,000到15,000条记录构建查询的最佳方法是什么,它将检索B中最新的(最大pk)记录,该记录对应于A中每条记录的A记录?这是否必须使用SQL代替Django ORM?
答案 0 :(得分:2)
创建一个帮助函数,用于从任何查询集中安全地提取“顶部”项。我在自己的Django应用程序中使用它。
def top_or_none(queryset):
"""Safely pulls off the top element in a queryset"""
# Extracts a single element collection w/ top item
result = queryset[0:1]
# Return that element or None if there weren't any matches
return result[0] if result else None
这使用slice operator to add a limit clause onto your SQL的一些技巧。
现在在需要的任何地方使用此功能来获取查询集的“顶部”项。在这种情况下,您希望获得给定A的前B项,其中B按降序pk排序,如下:
latest = top_or_none(B.objects.filter(a=my_a).order_by('-pk'))
最近在Django Aggregation中添加了“Max”功能可以帮助你获得最大pk,但在这种情况下我不喜欢这种解决方案,因为它增加了复杂性。
P.S。我真的不喜欢依赖'pk'字段来进行此类查询,因为有些RDBMS不保证顺序pks与逻辑创建顺序相同。如果我有一个我知道的表,我将需要以这种方式查询,我通常有自己的'创建'日期时间列,我可以使用它来代替pk。
根据评论进行修改:
如果你更喜欢使用queryset [0],你可以这样修改'top_or_none'函数:
def top_or_none(queryset):
"""Safely pulls off the top element in a queryset"""
try:
return queryset[0]
except IndexError:
return None
我最初没有提出这个问题,因为我认为queryset [0]会拉回整个结果集,然后取第0个项目。显然Django在这个场景中也增加了一个'LIMIT 1',所以它是我切片版本的安全替代品。
修改2
当然,您也可以利用Django的相关管理器构造,并根据您的偏好通过“A”对象构建查询集:
latest = top_or_none(my_a.b_set.order_by('-pk'))
答案 1 :(得分:0)
我不认为Django ORM可以做到这一点(但我之前一直很惊喜......)。如果有一个合理数量的A记录(或者如果你正在分页),我只会向A模型添加一个方法,该方法将返回这个“最新”的B记录。如果你想获得很多A记录,每个记录都有自己最新的B记录,我会选择SQL。
请记住,无论您选择哪条路线,您都需要在B表上使用合适的复合索引,可能会在order_by=('a_fk','-id')
子类中添加Meta