django_assert_queries.query_comparator

Utilities for comparing executed queries to expectations.

These are used internally for unit testing, but can also be useful when instrumenting code.

New in version 1.0.

Module Attributes

ExpectedQueries

A type representing list of expected queries.

Functions

compare_queries(queries, *[, ...])

Assert the number and complexity of queries.

Classes

CompareQueriesContext

Context for compared query results.

ExpectedQuery

An expected query for a query assertion.

QueryMismatch

Information on a mismatched query.

QueryMismatchedAttr

An attribute for a query that failed to meet expectations.

class django_assert_queries.query_comparator.QueryMismatchedAttr[source]

Bases: TypedDict

An attribute for a query that failed to meet expectations.

New in version 1.0.

name: str

The name of the attribute.

executed_value: str

The serialized version of the value from the executed query.

expected_value: str

The serialized version of the value from the expected query.

raw_executed_value: Any

The raw value from the executed query.

raw_expected_value: Any

The raw value from the expected query.

class django_assert_queries.query_comparator.QueryMismatch[source]

Bases: TypedDict

Information on a mismatched query.

New in version 1.0.

executed_query: Query

The query that was executed.

mismatched_attrs: List[QueryMismatchedAttr]

The list of mismatched attributes in this query.

index: int

The 0-based index of the executed query that this represents.

note: str | None

An optional note describing this query.

query_sql: List[str] | None

The generated SQL for the query.

subqueries: CompareQueriesContext | None

The results for any subquery matches.

traceback: List[str] | None

Lines of traceback showing where this query was executed.

class django_assert_queries.query_comparator.ExpectedQuery[source]

Bases: TypedDict

An expected query for a query assertion.

This is used for django_assert_queries.testing.assert_queries().

New in version 1.0.

__note__: NotRequired[str]

A custom note for the query, to help with query inspection.

annotations: NotRequired[Dict[str, BaseExpression]]

A dictionary containing applied annotations.

Keys are destination attribute names, and values are the annotation instances.

The default is empty.

distinct: NotRequired[bool]

Whether django.db.models.query.QuerySet.distinct() was used.

The default is False.

distinct_fields: NotRequired[Tuple[str, ...]]

A list of distinct fields.

These are field names passed to django.db.models.query.QuerySet.distinct().

The default is empty.

extra: NotRequired[Dict[str, Any]]

Extra state passed in the queryset.

This is state passed in calls to django.db.models.query.QuerySet.extra() when using select and select_params.

Each key maps to a key in select, and each value is a tuple containing the value in select and the corresponding value (if any) in select_params.

Values are normalized to collapse and strip whitespace, to help with comparison.

The default is empty.

extra_order_by: NotRequired[Sequence[str]]

Extra order-by values.

This is state passed in calls to django.db.models.query.QuerySet.extra() when using order_by.

The default is empty.

extra_tables: NotRequired[Sequence[str]]

Extra tables for the query.

This is state passed in calls to django.db.models.query.QuerySet.extra() when using tables.

The default is empty.

group_by: NotRequired[bool | Tuple[str, ...] | None]

The grouping of results.

This determines whether no fields will be grouped (None), all fields will be grouped (True), or specific expressions/field names are grouped (a tuple).

This is influenced by using django.db.models.query.QuerySet.annotate().

The default is None.

join_types: NotRequired[Dict[str, str]]

A mapping of joined table names to their join types.

limit: NotRequired[int | None]

The value for a LIMIT in the SELECT.

This will generally only need to be supplied if testing a query using QuerySet.exists() or when slicing results.

Django itself sometimes uses a default of None and sometimes a default currently of 21 (this exact value, and when it’s used, is considered an implementation detail in Django). Both of these will match a caller-provided limit value of None.

The default is None.

model: NotRequired[Type[Model]]

The model backing the queryset.

This represents the results that would be returned or altered by the query.

num_joins: NotRequired[int]

The number of tables joined.

The default is 0.

offset: NotRequired[int]

The value for an OFFSET in the SELECT.

The default is 0.

only_fields: NotRequired[Set[str]]

The specific fields being fetched, or None if fetching all fields.

The default is None.

order_by: NotRequired[Tuple[str, ...]]

The ordering criteria.

The default is empty.

select_for_update: NotRequired[bool]

Whether this is a select-for-update operation.

The default is False.

The table names involved in a select-related operation.

These are the names passed to django.db.models.query.QuerySet.select_related(). If called without any parameters, this would be True.

subqueries: NotRequired[ExpectedQueries | None]

Information on subqueries within this query.

subquery: NotRequired[bool]

Whether this is considered a subquery of another query.

The default is False.

tables: NotRequired[Set[str]]

The tables involved in the query.

The default is the model’s table name.

type: NotRequired[str]

The query type.

This would be one of DELETE, INSERT, SELECT, or UPDATE.

The default is SELECT.

values_select: NotRequired[Tuple[str, ...]]

A list of specified fields to return as values.

These are values passed in values() or values_list().

where: NotRequired[Q]

The query expression objects used to represent the filter on the query.

These are normalized to filter out empty or unnecessarily-nested queries, to ease comparison.

django_assert_queries.query_comparator.ExpectedQueries

A type representing list of expected queries.

Note

This type allows either a ExpectedQuery() or a plain dictionary of string-based keys. This is because with pyright (as of 1.1.332), the type of the right-hand-side of a += operation cannot be inferred. That makes it difficult to dynamically build expected queries.

Until/unless the situation improves, we aim for an ExpectedQuery() but allow a plain dictionary.

New in version 1.0.

alias of List[Union[ExpectedQuery, Dict[str, Any]]]

class django_assert_queries.query_comparator.CompareQueriesContext[source]

Bases: TypedDict

Context for compared query results.

This is provided and populated when using compare_queries().

This should not be populated by consumers, only by this library.

New in version 1.0.

has_mismatches: bool

Whether there are any mismatches found.

num_executed_queries: int

The number of queries that were executed.

num_expected_queries: int

The number of queries that were expected.

query_count_mismatch: bool

Whether the number of executed and expected queries are different.

query_mismatches: List[QueryMismatch]

The list of query expectation failures.

django_assert_queries.query_comparator.compare_queries(queries: Sequence[ExpectedQuery | Dict[str, Any]], *, _check_join_types: bool = True, _check_subqueries: bool = True) Iterator[CompareQueriesContext][source]

Assert the number and complexity of queries.

This provides advanced checking of queries, allowing the caller to match filtering, JOINs, ordering, selected fields, and more.

This takes a list of dictionaries with query information. Each contains the keys in ExpectedQuery.

New in version 1.0.

Parameters:
  • queries (list of ExpectedQuery) – The list of query dictionaries to compare executed queries against.

  • _check_join_types (bool, optional) –

    Whether to check join types.

    This is internal for compatibility with the old behavior for assert_queries() and will be removed in a future release without a deprecation period.

  • _check_subqueries (bool, optional) –

    Whether to check subqueries.

    This is internal for compatibility with the old behavior for assert_queries() and will be removed in a future release without a deprecation period.

Context:

dict – The context for compared queries.

This will only be populated after the context manager has finished. See CompareQueriesContext for details.