Skip to content

values() and values_list()

.values() and .values_list() return a full queryset of dicts / tuples (flat values, namedtuples). Every chained method applies the same .values() call to the chained queryset — qs.values("a").filter(x=1) is exactly qs.filter(x=1).values("a") — so all queryset semantics (slicing rules, HAVING, cursors, ambient tenant/soft-delete scope, connection choice) carry over. Chained methods use field and annotation names, as on the queryset; an expression passed to values(name=expression)/values_list(name=expression) is readable by that name too, and so is a renamed field: values(title="name").filter(title="a").order_by("-title") (a new name that is a field of the model keeps meaning that field).

Method Type What it does
filter() / exclude() / order_by() / distinct(*fields) / alias() / group_by() / all() / none() / limit() / offset() / using() / select_for_update() / with_cte() / after_cursor() / before_cursor() / all_tenants() / include_deleted() / only_deleted() chain Same as on the queryset, keeping the selected fields and the row shape. A filter on an aggregate annotation applies to the groups (HAVING).
annotate(**kwargs) chain Adds the annotations to the selected columns (after them) — see annotate()
values(...) / values_list(...) chain Replaces the selected fields (dicts ↔ tuples too). A query an aggregate groups by the selected fields stays grouped by them: values("author_id").annotate(n=Count("id")).values_list("n", flat=True) is one count per author.
qs[a:b] / qs[i] chain / terminal A slice composes with any slice already taken; an index is the one row at that position — IndexError when awaited if there is none; a negative index raises QueryError.
count() await The number of rows await qs returns — of groups for a grouped query, of distinct rows for a .distinct() one, the slice included — counted over the query as a derived table.
exists() await Whether await qs returns any row, the slice included.
aggregate(**kwargs) await When every row is a row of the source queryset (no grouping, no .distinct() over the selected fields, no slice, no selected field or ordering across a to-many relation), this is the queryset's own aggregate() and can read any field — see aggregate()
first() / last() terminal The first/last row in the ordering; unordered, a grouped query is ordered by its group key (the selected non-aggregate fields, or the .group_by() fields), any other by the primary key.
earliest(*fields) / latest(*fields) / get(*args, does_not_exist_exception=..., multiple_objects_returned_exception=..., **kwargs) terminal As on the queryset, returning a row. On a sliced query whose rows aren't one per model row (grouped, .distinct(), or multiplied by a to-many relation), these and last() raise QueryError — the slice is taken over rows the queryset can't narrow to.
iterator(chunk_size=1000) async generator Pages through the rows — see iterator()
stream(chunk_size=1000) async generator A cursor, like QuerySet.stream() — inside a transaction.
union(*others, all=False) / intersection(*others) / difference(*others) chain A queryset of the combined rows — see below.
update(**kwargs) await Updates the rows of the source queryset — the selected fields don't matter. QueryError on a grouped query (its rows are groups, not model rows) and, as in Django, after a slice, offset() or distinct(*fields).
delete() / contains() / only() / defer() / select_related() / prefetch_related() — QueryError — call them on the queryset before .values().
sql() / explain() sync / async def As on the queryset.

annotate()

Adds the annotations to the selected columns (after them). An aggregate groups the rows by the other selected columns: Book.objects.all().values("author_id").annotate(n=Count("id")) returns one row per author. The order matters: an aggregate annotated before values()/values_list() (also by .alias()), or passed to them as a keyword argument, is computed per model row — Author.objects.annotate(n=Count("books")).values("country", "n") returns one row per author, grouped by the primary key too. A .filter(books__...) chained after values(...).annotate(n=Count("books")) reuses the aggregate's JOIN, so the count covers only the matching books (see Aggregates and to-many filters). A flat=True values_list() keeps its one column — the annotation still groups and filters it: values_list("author__name", flat=True).annotate(n=Count("id")).filter(n__gt=3). Without selected fields (values()), the annotation joins every field.

aggregate()

When every row is a row of the source queryset (no grouping, no .distinct() over the selected fields, no slice, no selected field or ordering across a to-many relation), this is the queryset's own aggregate() and can read any field. Otherwise it runs over the rows the query returns, as a derived table, and can read only the selected columns — by output name, or by the field name a renamed key selects; anything else raises QueryError, an annotation a flat=True values_list() doesn't select included. values("author_id").annotate(n=Count("id")).aggregate(most=Max("n")), values_list("rating", flat=True).distinct().aggregate(total=Sum("rating")), order_by("-rating")[:3].aggregate(...). A query reading a window function aggregates over the derived table too.

iterator()

Pages through the rows. Without an order_by(), pages follow Meta.ordering, else the group key of a grouped query, else the primary key; the columns making the ordering unique per row are appended — the group key of a grouped query, the selected fields of a .distinct() one, otherwise the primary key (when the ordering isn't unique already) and every selected field across a to-many relation. Pages by keyset (safe under concurrent deletes) when every ordering column is a selected field of the model itself, otherwise by OFFSET. The query's own slice and after_cursor() bound the whole iteration.

.distinct() ordered by a field it doesn't select

SELECT DISTINCT has to select every ORDER BY column, so the ordering column is selected too: rows differing only in it stay apart, and a selected value may come several times. The rows hold only the fields asked for:

# ratings 5 "sci", 4 "art", 3 "sci", 3 "art"
await Book.objects.all().order_by("-rating").distinct().values_list("subject", flat=True)  # ["sci", "art", "sci", "art"]

To get each value once, order by the selected fields only, or drop the ordering with order_by().

Set operations

union()/intersection()/difference() of .values()/.values_list() queries return a queryset of the combined rows. Every branch selects the same number of columns (QueryError otherwise); the rows take the first branch's shape (dicts, tuples, flat values, namedtuples) and names, and each column decodes through the first branch that knows its field. A branch may be ordered, sliced or itself a set operation (it is combined as a derived table); branches may come from different models. Chained calls combine each new branch with the whole result so far, as for model querysets. Such a union supports order_by() by output names, limit()/offset()/slices/index, count(), exists(), first()/last() (unordered: by every output column), get(), aggregate() (reading output names), iterator() (OFFSET paging, every output column as a tie-breaker), stream(), sql()/explain(), and works as an __in value: Author.objects.filter(id__in=a.values_list("author_id", flat=True).union(b...)). filter()/exclude()/annotate()/update()/delete() on it raise QueryError — apply them to the branches. .values(...)/.values_list(...) on a union of model querysets apply the call to every branch, keeping the union's ordering (by fields the rows select) and slice. Combining a model queryset with a values query raises QueryError.

Relations and pk in field paths

A field path may end on a relation or on pk, everywhere a field path is accepted — values()/values_list(), order_by(), group_by(), distinct(<fields>), F() and aggregates:

  • a forward FK/O2O name (values("author")) reads its own key column (author_id) with no JOIN — the value stays even when the related row is hidden by its default scope (tenant, soft delete, Meta.manager), like the column itself; only("author") loads that column;
  • a to-many relation (values("tags"), values("books")) or a reverse one-to-one reads the related primary key — a row per related row, NULL for a row without one — through the same JOIN as values("tags__id"), scoped by the related model's default scope;
  • a trailing pk (values("tags__pk"), values("author__pk"), order_by("tags__pk"), group_by("author__pk"), only("pk")) reads the primary key field of the model it reaches — through the JOIN, so author__pk is NULL for a hidden author while author keeps the column value.

The output keeps the name you passed ({"tags": 1}, row.tags of a named=True row). A key read this way works like any selected field: values("tags").annotate(n=Count("id")) groups by the tag (a row per tag, one NULL group for the rows without a tag — the key is the primary key, so an aggregate over another to-many relation is correct next to it), and it combines with .distinct(), order_by(), count(), aggregate(), iterator(), union() and __in subqueries (Tag.objects.filter(id__in=Book.objects.filter(...).values("tags"))). A composite primary key (or a relation to one) is read as a tuple of its components — values("pk"), values_list("shelf", flat=True) give (1, 2), and None when every component is NULL; group_by(), order_by() ("pk"/"-pk" and Meta.ordering too) and distinct(<fields>) use every component. Renamed (values(key="pk")), it is the same key under the new name: filter(key=(1, 2)), filter(key__in=[...]), order_by("-key") and values("key") read its components as pk does. Count("shelf") counts the rows with a key, Count("shelf", distinct=True) the distinct keys, never a NULL one. F() of such a relation raises QueryError naming its components.

Date parts in field paths

A field path may end on a part of a date, time or datetime field — in values()/values_list(), order_by(), group_by() and distinct(<fields>):

await Book.objects.all().values("added_at__year")
await Book.objects.all().values_list("added_at__hour", "added_at__date")
await Book.objects.all().values(hour="added_at__hour")
await Book.objects.all().order_by("-added_at__month")
await Book.objects.all().order_by("added_at__date").distinct("added_at__date")  # PostgreSQL only - DISTINCT ON
await Book.objects.annotate(count=Count("id")).group_by("added_at__year").values("added_at__year", "count")
Part Value
year, iso_year, quarter, month, week, day an integer
week_day 1 = Sunday ... 7 = Saturday
iso_week_day 1 = Monday ... 7 = Sunday
hour, minute, second, microsecond an integer
date, time a datetime's date / time of day

A DatetimeField has every part. A DateField has only the calendar parts (year ... day), a TimeField only the time-of-day ones (hour ... microsecond); a part the field doesn't have raises FieldError. A path may go through relations first: book__added_at__year. A datetime's part is taken in the current zone — Timezone.override(), else the configured one — as the __year/__date lookups take it; under use_timezone=True a time comes back with the zone's offset, as a TimeField value does.

distinct() takes an annotation's name as well: .annotate(year=ExtractYear("added_at")).distinct("year").order_by("year", "id"). On PostgreSQL the zone of an Extract() is written into the SQL as a literal, so one part in SELECT, ORDER BY and DISTINCT ON is the same expression; a filter (added_at__hour=...) still binds the zone as a parameter.