MCPcopy
hub / github.com/django/django / split_exclude

Method split_exclude

django/db/models/sql/query.py:2112–2179  ·  view source on GitHub ↗

When doing an exclude against any kind of N-to-many relation, we need to use a subquery. This method constructs the nested query, given the original exclude filter (filter_expr) and the portion up to the first N-to-many relation field. For example, if the or

(self, filter_expr, can_reuse, names_with_path)

Source from the content-addressed store, hash-verified

2110 return transform
2111
2112 def split_exclude(self, filter_expr, can_reuse, names_with_path):
2113 """
2114 When doing an exclude against any kind of N-to-many relation, we need
2115 to use a subquery. This method constructs the nested query, given the
2116 original exclude filter (filter_expr) and the portion up to the first
2117 N-to-many relation field.
2118
2119 For example, if the origin filter is ~Q(child__name='foo'), filter_expr
2120 is ('child__name', 'foo') and can_reuse is a set of joins usable for
2121 filters in the original query.
2122
2123 We will turn this into equivalent of:
2124 WHERE NOT EXISTS(
2125 SELECT 1
2126 FROM child
2127 WHERE name = 'foo' AND child.parent_id = parent.id
2128 LIMIT 1
2129 )
2130 """
2131 # Generate the inner query.
2132 query = self.__class__(self.model)
2133 query._filtered_relations = self._filtered_relations
2134 filter_lhs, filter_rhs = filter_expr
2135 if isinstance(filter_rhs, OuterRef):
2136 filter_rhs = OuterRef(filter_rhs)
2137 elif isinstance(filter_rhs, F):
2138 filter_rhs = OuterRef(filter_rhs.name)
2139 query.add_filter(filter_lhs, filter_rhs)
2140 query.clear_ordering(force=True)
2141 # Try to have as simple as possible subquery -> trim leading joins from
2142 # the subquery.
2143 trimmed_prefix, contains_louter = query.trim_start(names_with_path)
2144
2145 col = query.select[0]
2146 select_field = col.target
2147 alias = col.alias
2148 if alias in can_reuse:
2149 pk = select_field.model._meta.pk
2150 # Need to add a restriction so that outer query's filters are in
2151 # effect for the subquery, too.
2152 query.bump_prefix(self)
2153 lookup_class = select_field.get_lookup("exact")
2154 # Note that the query.select[0].alias is different from alias
2155 # due to bump_prefix above.
2156 lookup = lookup_class(pk.get_col(query.select[0].alias), pk.get_col(alias))
2157 query.where.add(lookup, AND)
2158 query.external_aliases[alias] = True
2159 else:
2160 lookup_class = select_field.get_lookup("exact")
2161 lookup = lookup_class(col, ResolvedOuterRef(trimmed_prefix))
2162 query.where.add(lookup, AND)
2163
2164 condition, needed_inner = self.build_filter(Exists(query))
2165
2166 if contains_louter:
2167 or_null_condition, _ = self.build_filter(
2168 ("%s__isnull" % trimmed_prefix, True),
2169 current_negated=True,

Callers 1

build_filterMethod · 0.95

Calls 11

build_filterMethod · 0.95
OuterRefClass · 0.90
ResolvedOuterRefClass · 0.90
ExistsClass · 0.90
add_filterMethod · 0.80
clear_orderingMethod · 0.80
trim_startMethod · 0.80
bump_prefixMethod · 0.80
get_lookupMethod · 0.45
get_colMethod · 0.45
addMethod · 0.45

Tested by

no test coverage detected