Skip to main content

strawberry-django-aggregates

Hasura-shape aggregations over Django querysets in Strawberry GraphQL.

count · count_distinct · sum · avg · min · max · stddev · variance · bool_and · bool_or · array_agg · string_agg — composed with multi-level group_by, having filters, and ordering on aggregate aliases. Inspired by Hasura's <table>_aggregate, PostGraphile's pg-aggregates, and Odoo 18's _read_group. Built for strawberry-django over PostgreSQL and SQLite.

from decimal import Decimal
from datetime import datetime
from strawberry import auto
import strawberry, strawberry_django
from strawberry_django_aggregates import AggregateBuilder

from .models import Order

@strawberry_django.type(Order)
class OrderType:
    id: auto
    customer: "CustomerType"
    total: Decimal
    status: str
    created_at: datetime

# One call wires count/sum/avg/min/max + group_by + having into the schema:
order_aggs = AggregateBuilder(
    model=Order,
    aggregate_fields=["total"],
    group_by_fields=["customer", "status", "created_at"],
).build()

@strawberry.type
class Query:
    orders_aggregate = order_aggs.aggregate_field
    orders_group_by  = order_aggs.group_by_field

Generates a fully-typed GraphQL surface:

type Query {
  ordersAggregate(filter: OrderFilter): OrderAggregate!
  ordersGroupBy(
    filter:    OrderFilter
    groupBy:   [OrderGroupBySpec!]!
    having:    OrderHaving
    orderBy:   [OrderGroupOrder!]
    pagination: OffsetPagination
  ): OrderGroupedResult!
}

type OrderAggregate {
  count:           Int!
  countDistinct(field: OrderCountableField!): Int!
  sum:             OrderSumFields
  avg:             OrderAvgFields
  min:             OrderMinFields
  max:             OrderMaxFields
  stddev:          OrderStddevFields    # Postgres only
  variance:        OrderVarianceFields  # Postgres only
}

type OrderGrouped {
  key:   OrderGroupKey!   # composite — every requested groupBy field present
  count: Int!
  sum:   OrderSumFields
  # ... no recursive subgroups field — flat results
}

Features

  • Hasura-canonical schema shape. <Model>Aggregate { count, countDistinct, sum, avg, min, max, stddev, variance, boolAnd, boolOr, arrayAgg, stringAgg }.
  • Odoo-grade group-by. Multi-level via composite keys (flat result rows), dual date-granularity tracks (date_trunc returning DateTime AND date_part::int returning Int), timezone-correct bucketing.
  • HAVING with aggregate aliases. { countGt: 5, sumTotalGt: 1000 } — typed inputs generated per measure.
  • Ordering on aggregates. [{ field: "total:sum", direction: DESC }] — fail-loud on unknown terms (Odoo's pre-17 silent-drop bug avoided).
  • Standalone backend primitive. compute_aggregation(qs, group_by, aggregates, having, order_by, ...) is callable from any Python context — DRF view, Celery task, admin script, MCP tool — not just GraphQL resolvers.
  • Composable group-key projection. A custom grouped envelope can pass the same group_by_expressions mapping to compute_aggregation and AggregateBuilder.count_groups for selected to-one scalar/date axes. Native aliases, temporal bucketing, HAVING, rows, and exact counts stay aligned; unsupported axes fail loud.
  • Exact group cardinality. AggregateBuilder.count_groups(...) returns the database-side group count before pagination for custom grouped envelopes, including filters, granularity, JSON paths, and HAVING.
  • Determinism. Type generation produces byte-identical SDL for the same inputs.
  • No magic. Every operator, every granularity, every type is whitelisted.

Non-goals

  • Cross-database aggregation. PostgreSQL + SQLite only. SQLite degrades gracefully on array_agg/string_agg/stddev/variance — those operators raise OperatorNotSupportedError at resolver entry.
  • Auto-traversal of one-to-many / many-to-many for measures. This is the silent row-multiplication footgun Odoo refuses to ship; we follow. array_agg is the explicit escape hatch.
  • Permission integration. The library expects a pre-scoped queryset — the caller has already applied accessible_by(user) or equivalent. This keeps the library compatible with django-guardian, django-rules, django-rebac (when shipped), or hand-rolled permission systems.

Status

Beta (v0.10.0). The schema shape, operator vocabulary, and compute_aggregation signature are stable for early adopters, but minor-level iteration is still expected before a 1.0 stability commitment — see docs/SPEC.md § 16. Runtime: Python 3.14, Django 6.0.

Documentation

  • Full contract: docs/SPEC.md — operator catalog, granularity tracks, HAVING semantics, ordering rules, timezone handling, and the Odoo-derived footgun audit.
  • Naming and wire vocabulary: docs/TERMINOLOGY.md
  • Contributor quality gate: CONTRIBUTING.md

License

BSD-3-Clause.

Metadata

Release files for strawberry-django-aggregates 0.13.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for strawberry-django-aggregates 0.13.0
File Size Uploaded
strawberry_django_aggregates-0.13.0.tar.gz 163.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for strawberry-django-aggregates 0.13.0
File Interpreter ABI Platform
strawberry_django_aggregates-0.13.0-py3-none-any.whl Python 3 none any Details

Total release size: 269.5 kB

Release files / strawberry_django_aggregates-0.13.0.tar.gz

Download URL strawberry_django_aggregates-0.13.0.tar.gz
Size 163.4 kB
Tags Source
SHA-256 checksum
How to use checksums
345856b93720d19c689800fff4c9b2e0fbd27eed4c695868832073687f6d9608
BLAKE2b-256 checksum
How to use checksums
f9098c777ddd9b548710d15145ff794960190ea1352b22f0f42b94fe75c51f60
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / strawberry_django_aggregates-0.13.0-py3-none-any.whl

Download URL strawberry_django_aggregates-0.13.0-py3-none-any.whl
Size 106.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e23faf794d90cfdc41479e72bc37a217451d827a55f8395f9febbbaf6bbe296a
BLAKE2b-256 checksum
How to use checksums
175fe96d9e3ba64e897144c347d33f2d4d408489c8834542acf9fc78d838a360
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.13.0 This release

2 release files

0.10.0

2 release files

0.9.1

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page