feat: add DISTINCT ON support for PostgreSQL.#2211
Conversation
|
@VladislavYar , this PR is helpful — let's go ahead with it. Said by AI (Claude/Codex): Findings
However, many common query chains are not DB-bound yet when distinct() is called, for example: Tournament.filter(name="x").distinct("name") These start from manager.get_queryset(), so self.query is still the generic placeholder builder. As a result, this This check should be based on the chosen/model DB capability or deferred until query construction.
Test Coverage GapThe new tests cover Tournament.all().distinct("name"), but they do not cover:
Those cases should be added before merging. |
Description
Added
DISTINCT ON (fields)support for PostgreSQL toQuerySet.distinct(*fields).Previously,
.distinct()only supported plainDISTINCT(no arguments). Now, passing fieldnames generates
DISTINCT ON (fields)on PostgreSQL, keeping one row per unique combinationof the specified fields. The feature is fully propagated to
.values(),.values_list(),and
.only().Also added:
skipCapabilitydecorator totortoise.contrib.test— the inverse ofrequireCapability,skips a test when the specified capabilities match.
_apply_db()helper in_ChooseDBMixinthat consistently sets the DB connection andswitches the query builder to
PostgreSQLQueryBuilderacross all query classes.Motivation and Context
PostgreSQL's
DISTINCT ONis a powerful feature that standardDISTINCTcannot replace —it allows selecting one representative row per group without a
GROUP BY, while retainingfull model objects. This is commonly needed for "latest per group" or "first per category"
queries.
How Has This Been Tested?
Added
tests/test_distinct.pycovering:DISTINCT ONwith and withoutORDER BYDISTINCT ONfields.values_list()— single field, multiple fields, field outsideDISTINCT ON.values()— same variations.only()ORDER BYrespects the selected row within each groupOperationalErrorwhenORDER BYdoesn't start withDISTINCT ONfieldsOperationalErrorwhen used on a non-PostgreSQL databaseChecklist: