| 550 | 550 | Perform a COUNT() query using the current filter constraints. |
| 551 | 551 | """ |
| 552 | 552 | obj = self.clone() |
| 553 | # Strip unused annotations to optimize count queries | |
| 554 | obj.strip_unused_annotations() | |
| 553 | 555 | obj.add_annotation(Count("*"), alias="__count", is_summary=True) |
| 554 | 556 | return obj.get_aggregation(using, ["__count"])["__count"] |
| 555 | 557 | |
| 1101 | 1103 | def add_annotation(self, annotation, alias, is_summary=False, select=True): |
| 1102 | 1104 | """Add a single annotation expression to the Query.""" |
| 1103 | 1105 | self.check_alias(alias) |
| 1106 | # Track annotation references before resolution | |
| 1107 | self._track_annotation_reference(annotation, alias) | |
| 1104 | 1108 | annotation = annotation.resolve_expression( |
| 1105 | 1109 | self, allow_joins=True, reuse=None, summarize=is_summary |
| 1106 | 1110 | ) |
| 1905 | 1909 | def _gen_col_aliases(cls, exprs): |
| 1906 | 1910 | yield from (expr.alias for expr in cls._gen_cols(exprs)) |
| 1907 | 1911 | |
| 1912 | def get_referenced_annotations(self): | |
| 1913 | """ | |
| 1914 | Return a set of annotation names that are referenced in this query. | |
| 1915 | Annotations are considered referenced if they appear in: | |
| 1916 | - WHERE clause conditions | |
| 1917 | - ORDER BY clauses | |
| 1918 | - Other annotations (as dependencies) | |
| 1919 | """ | |
| 1920 | referenced = set() | |
| 1921 | ||
| 1922 | # Check WHERE clause for annotation references | |
| 1923 | if self.where: | |
| 1924 | for col in self._gen_cols([self.where], include_external=True): | |
| 1925 | if hasattr(col, 'alias') and col.alias in self.annotations: | |
| 1926 | referenced.add(col.alias) | |
| 1927 | ||
| 1928 | # Check ORDER BY clause for annotation references | |
| 1929 | for order_expr in self.order_by: | |
| 1930 | # Handle string references to annotations | |
| 1931 | if isinstance(order_expr, str) and order_expr in self.annotations: | |
| 1932 | referenced.add(order_expr) | |
| 1933 | else: | |
| 1934 | # Handle expression references | |
| 1935 | for col in self._gen_cols([order_expr], include_external=True): | |
| 1936 | if hasattr(col, 'alias') and col.alias in self.annotations: | |
| 1937 | referenced.add(col.alias) | |
| 1938 | ||
| 1939 | # Check tracked annotation references | |
| 1940 | if hasattr(self, '_annotation_references'): | |
| 1941 | for alias, refs in self._annotation_references.items(): | |
| 1942 | for ref in refs: | |
| 1943 | if ref in self.annotations and ref != alias: | |
| 1944 | referenced.add(ref) | |
| 1945 | ||
| 1946 | return referenced | |
| 1947 | ||
| 1948 | def _track_annotation_reference(self, annotation, alias): | |
| 1949 | """ | |
| 1950 | Track references from this annotation to other annotations. | |
| 1951 | This is called before the annotation is resolved. | |
| 1952 | """ | |
| 1953 | if not hasattr(self, '_annotation_references'): | |
| 1954 | self._annotation_references = {} | |
| 1955 | ||
| 1956 | def find_refs(expr): | |
| 1957 | """Find annotation references in an expression.""" | |
| 1958 | from django.db.models.expressions import F | |
| 1959 | refs = set() | |
| 1960 | if isinstance(expr, F): | |
| 1961 | refs.add(expr.name) | |
| 1962 | elif hasattr(expr, 'get_source_expressions'): | |
| 1963 | for source_expr in expr.get_source_expressions(): | |
| 1964 | refs.update(find_refs(source_expr)) | |
| 1965 | return refs | |
| 1966 | ||
| 1967 | self._annotation_references[alias] = find_refs(annotation) | |
| 1968 | ||
| 1969 | def strip_unused_annotations(self): | |
| 1970 | """ | |
| 1971 | Remove annotations that are not referenced in the query. | |
| 1972 | This is used to optimize count queries by removing unnecessary annotations. | |
| 1973 | """ | |
| 1974 | if not self.annotations: | |
| 1975 | return | |
| 1976 | ||
| 1977 | referenced = self.get_referenced_annotations() | |
| 1978 | ||
| 1979 | # Keep only referenced annotations | |
| 1980 | unused_annotations = set(self.annotations.keys()) - referenced | |
| 1981 | for alias in unused_annotations: | |
| 1982 | del self.annotations[alias] | |
| 1983 | ||
| 1984 | # Clear annotation cache if it exists | |
| 1985 | if self._annotation_select_cache is not None: | |
| 1986 | self._annotation_select_cache = None | |
| 1987 | ||
| 1908 | 1988 | def resolve_ref(self, name, allow_joins=True, reuse=None, summarize=False): |
| 1909 | 1989 | annotation = self.annotations.get(name) |
| 1910 | 1990 | if annotation is not None: |
| Test Name | Status |
|---|---|
test_unreferenced_aggregate_annotation_pruned (aggregation.tests.AggregateAnnotationPruningTests) | Fail |
Subquery annotations must be included in the GROUP BY if they use | Fail |
test_non_aggregate_annotation_pruned (aggregation.tests.AggregateAnnotationPruningTests) | Pass |
test_unused_aliased_aggregate_pruned (aggregation.tests.AggregateAnnotationPruningTests) | Pass |
test_referenced_aggregate_annotation_kept (aggregation.tests.AggregateAnnotationPruningTests) | Pass |
test_add_implementation (aggregation.tests.AggregateTestCase) | Pass |
test_aggregate_alias (aggregation.tests.AggregateTestCase) | Pass |
test_aggregate_annotation (aggregation.tests.AggregateTestCase) | Pass |
test_aggregate_in_order_by (aggregation.tests.AggregateTestCase) | Pass |
test_aggregate_join_transform (aggregation.tests.AggregateTestCase) | Pass |
test_aggregate_multi_join (aggregation.tests.AggregateTestCase) | Pass |
test_aggregate_over_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_aggregate_over_complex_annotation (aggregation.tests.AggregateTestCase) | Pass |
test_aggregate_transform (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_after_annotation (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_compound_expression (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_expression (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_group_by (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_integer (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_not_in_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_passed_another_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_unset (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_unsupported_by_count (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_using_date_from_database (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_using_date_from_python (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_using_datetime_from_database (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_using_datetime_from_python (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_using_decimal_from_database (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_using_decimal_from_python (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_using_duration_from_database (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_using_duration_from_python (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_using_time_from_database (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_using_time_from_python (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_default_zero (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_exists_annotation (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_exists_multivalued_outeref (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_expressions (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_filter_exists (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_nested_subquery_outerref (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_order_by_not_selected_annotation_values (aggregation.tests.AggregateTestCase) | Pass |
Random() is not included in the GROUP BY when used for ordering. | Pass |
Subquery annotations are excluded from the GROUP BY if they are | Pass |
test_aggregation_subquery_annotation_exists (aggregation.tests.AggregateTestCase) | Pass |
test_aggregation_subquery_annotation_related_field (aggregation.tests.AggregateTestCase) | Pass |
Subquery annotations and external aliases are excluded from the GROUP | Pass |
test_aggregation_subquery_annotation_values_collision (aggregation.tests.AggregateTestCase) | Pass |
test_alias_sql_injection (aggregation.tests.AggregateTestCase) | Pass |
test_annotate_basic (aggregation.tests.AggregateTestCase) | Pass |
test_annotate_defer (aggregation.tests.AggregateTestCase) | Pass |
test_annotate_defer_select_related (aggregation.tests.AggregateTestCase) | Pass |
test_annotate_m2m (aggregation.tests.AggregateTestCase) | Pass |
test_annotate_ordering (aggregation.tests.AggregateTestCase) | Pass |
test_annotate_over_annotate (aggregation.tests.AggregateTestCase) | Pass |
test_annotate_values (aggregation.tests.AggregateTestCase) | Pass |
test_annotate_values_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_annotate_values_list (aggregation.tests.AggregateTestCase) | Pass |
test_annotated_aggregate_over_annotated_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_annotation (aggregation.tests.AggregateTestCase) | Pass |
test_annotation_expressions (aggregation.tests.AggregateTestCase) | Pass |
test_arguments_must_be_expressions (aggregation.tests.AggregateTestCase) | Pass |
test_avg_decimal_field (aggregation.tests.AggregateTestCase) | Pass |
test_avg_duration_field (aggregation.tests.AggregateTestCase) | Pass |
test_backwards_m2m_annotate (aggregation.tests.AggregateTestCase) | Pass |
test_coalesced_empty_result_set (aggregation.tests.AggregateTestCase) | Pass |
test_combine_different_types (aggregation.tests.AggregateTestCase) | Pass |
test_complex_aggregations_require_kwarg (aggregation.tests.AggregateTestCase) | Pass |
test_complex_values_aggregation (aggregation.tests.AggregateTestCase) | Pass |
test_count (aggregation.tests.AggregateTestCase) | Pass |
test_count_distinct_expression (aggregation.tests.AggregateTestCase) | Pass |
test_count_star (aggregation.tests.AggregateTestCase) | Pass |
.dates() returns a distinct set of dates when applied to a | Pass |
test_decimal_max_digits_has_no_effect (aggregation.tests.AggregateTestCase) | Pass |
test_distinct_on_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_empty_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_empty_result_optimization (aggregation.tests.AggregateTestCase) | Pass |
test_even_more_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_exists_extra_where_with_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_exists_none_with_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_expression_on_aggregation (aggregation.tests.AggregateTestCase) | Pass |
test_filter_aggregate (aggregation.tests.AggregateTestCase) | Pass |
Filtering against an aggregate requires the usage of the HAVING clause. | Pass |
test_filtering (aggregation.tests.AggregateTestCase) | Pass |
test_fkey_aggregate (aggregation.tests.AggregateTestCase) | Pass |
Exists annotations are included in the GROUP BY if they are | Pass |
Subquery annotations are included in the GROUP BY if they are | Pass |
An annotation included in values() before an aggregate should be | Pass |
test_more_aggregation (aggregation.tests.AggregateTestCase) | Pass |
test_multi_arg_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_multiple_aggregates (aggregation.tests.AggregateTestCase) | Pass |
An annotation not included in values() before an aggregate should be | Pass |
test_nonaggregate_aggregation_throws (aggregation.tests.AggregateTestCase) | Pass |
test_nonfield_annotation (aggregation.tests.AggregateTestCase) | Pass |
test_order_of_precedence (aggregation.tests.AggregateTestCase) | Pass |
test_related_aggregate (aggregation.tests.AggregateTestCase) | Pass |
test_reverse_fkey_annotate (aggregation.tests.AggregateTestCase) | Pass |
test_single_aggregate (aggregation.tests.AggregateTestCase) | Pass |
Sum on a distinct() QuerySet should aggregate only the distinct items. | Pass |
test_sum_duration_field (aggregation.tests.AggregateTestCase) | Pass |
Subqueries do not needlessly contain ORDER BY, SELECT FOR UPDATE or | Pass |
Aggregation over sliced queryset works correctly. | Pass |
Doing exclude() on a foreign model after annotate() doesn't crash. | Pass |
test_values_aggregation (aggregation.tests.AggregateTestCase) | Pass |
test_values_annotation_with_expression (aggregation.tests.AggregateTestCase) | Pass |
Loading...
Ridges.AI© 2025 Ridges AI. Building the future of decentralized AI development.
