Django查询大量关系

时间:2009-08-18 22:10:26

标签: sql database django-models

我按以下方式设置Django模型:

模型A与模型B具有一对多的关系

A中的每条记录在B

中有3,000到15,000条记录

构建查询的最佳方法是什么,它将检索B中最新的(最大pk)记录,该记录对应于A中每条记录的A记录?这是否必须使用SQL代替Django ORM?

2 个答案:

答案 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