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_truncreturningDateTimeANDdate_part::intreturningInt), 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. - Computed rows.
make_row_model(...)declares the columns of non-table rows, andcompute_row_aggregation(rows, model=..., ...)groups them in memory with the same types, translators, key shapers and result rows as a queryset (SPEC § 20). - Composable group-key projection. A custom grouped envelope can pass the
same
group_by_expressionsmapping tocompute_aggregationandAggregateBuilder.count_groupsfor 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, andHAVING. - 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 raiseOperatorNotSupportedErrorat 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_aggis 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.14.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| strawberry_django_aggregates-0.14.0.tar.gz | 179.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| strawberry_django_aggregates-0.14.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 294.6 kB
Release files / strawberry_django_aggregates-0.14.0.tar.gz
| Download URL | strawberry_django_aggregates-0.14.0.tar.gz |
|---|---|
| Size | 179.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a837203d4299a6d80ccf1b4880f3c5e402f2c9e9e73ecc9852859403805a17fc
|
|
BLAKE2b-256 checksum How to use checksums |
ca3e739c73f072e4d43d68b4918319f76fbb6d23420420152a9b1cf27b247c39
|
| 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.14.0-py3-none-any.whl
| Download URL | strawberry_django_aggregates-0.14.0-py3-none-any.whl |
|---|---|
| Size | 115.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
29a5652b679aa0897f28096d49805e07453537d57cfe96b3d8680a8a3dd7e81b
|
|
BLAKE2b-256 checksum How to use checksums |
4815513e15531c95e737f53f565bb27277b7b05f16a503df7cb2cb51372ff363
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for strawberry-django-aggregates 0.14.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.