使用子查询聚合的改进api

django-sql-utils的Python项目详细描述


https://travis-ci.org/martsberger/django-sql-utils.svg?branch=master

django sql实用程序

这个包提供了使用django querysets的实用程序,以便 您可以使用自己喜欢的api生成所需的sql。

子查询聚合

django中的计数聚合:

Parent.objects.annotate(child_count=Count('child'))

生成SQL,如下所示:

SELECT parent.*, Count(child.id) as child_count
FROM parent
JOIN child on child.parent_id = parent.id
GROUP BY parent.id

在许多情况下,这不如在子查询中执行计数。 而不是加入:

SELECT parent.*,
       (SELECT Count(id)
        FROM child
        WHERE parent_id = parent.id) as child_count
FROM parent

django允许我们使用子查询和outerref类生成此sql:

subquery = Subquery(Child.objects.filter(parent_id=OuterRef('id')).order_by()
                    .values('parent').annotate(count=Count('pk'))
                    .values('count'), output_field=IntegerField())
Parent.objects.annotate(child_count=Coalesce(subquery, 0))

天哪!想清楚上面所说的每件事都在做些什么并不容易 代码,对维护不是特别好。SubQueryAggregates允许 你要忘记所有的复杂性,并生成这样的子查询计数:

Parent.objects.annotate(child_count=SubqueryCount('child'))

呸!更容易阅读和理解。它与原来的count是相同的api 只是指定子查询版本。

存在的更简单的API < EH3>

如果您有一个父/子关系(child有一个到父的foreignkey),则可以注释queryset 具有布尔值的父对象,该布尔值指示父对象是否有子对象:

from django.db.models import Exists

parents = Parent.objects.annotate(
    has_children=Exists(Child.objects.filter(parent=OuterRef('pk'))
)

这比需要的要多一些,因此我们提供了一个更简单的API:

from sql_util.utils import Exists

parents = Parent.objects.annotate(
    has_children=Exists('child')
)

子QuerySet可以用关键字参数过滤。例如:

parents = Parent.objects.annotate(
    has_child_named_John = Exists('child', filter=Q(name='John'))
)
<> > > >版本也可以采用QuestSeSET作为第一个参数并表现得恰如其分 Django存在一个类,所以您可以在任何地方使用它而不必担心名称混淆。

安装和使用

从pypi安装:

pip install django-sql-utils

然后您可以:

from sql_util.utils import SubqueryCount

如上图所示。

除了subquerycount之外,此软件包还提供

  • 子查询min
  • 子查询最大值
  • 子查询
  • 子查询avg

如果要使用其他聚合,可以使用 泛型类。例如,如果要使用postgres'arrayagg 为每个父节点获取子节点的数组。name

from django.contrib.postgres.aggregates import ArrayAgg

aggregate = SubqueryAggregate('child__name', aggregate=ArrayAgg)
Parent.objects.annotate(child_names=aggregate)

或子类subqueryaggregate:

from django.contrib.postgres.aggregates import ArrayAgg

class SubqueryArrayAgg(SubqueryAggregate)
    aggregate = ArrayAgg
    unordered = True

Parent.objects.annotate(avg_child_age=SubqueryArrayAgg('child__age'))

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
在Eclipse中使用多个调用在一行上打印java   javajackson序列化问题。只有同一实体的第一个对象可以很好地序列化   Java中Deflate函数的等价充气   使用customlitview的java Android actionbar搜索   java“<T>T get()”是什么意思?(它有用吗?)   目标c使用CommonCrypto使用AES256加密,使用OpenSSL或Java解密   java在运行时更新资源文件   fileinputstream在java中访问并将数据写入现有文件   带集群的java Android Mapbox我希望每个功能都有不同的标记图像   java JDK8>JDK10:PKIX路径生成失败:SunCertPathBuilderException:找不到请求目标的有效证书路径   java使用Hk2生成具有指定构造函数参数的实例   为什么这个系统。出来Java中的println()打印到控制台?   java目录和文件名连接不起作用   使用mockito和通配符绘图的java