mirror of
https://github.com/django/django.git
synced 2025-11-28 22:49:09 +00:00
Refs #24267 -- Implemented lookups for related fields
Previously related fields didn't implement get_lookup, instead related fields were treated specially. This commit removed some of the special handling. In particular, related fields return Lookup instances now, too. Other notable changes in this commit is removal of support for annotations in names_to_path().
This commit is contained in:
parent
8654c6a732
commit
b68212f539
6 changed files with 219 additions and 94 deletions
|
|
@ -17,7 +17,8 @@ from django.db import DEFAULT_DB_ALIAS, connections
|
|||
from django.db.models.aggregates import Count
|
||||
from django.db.models.constants import LOOKUP_SEP
|
||||
from django.db.models.expressions import Col, Ref
|
||||
from django.db.models.query_utils import Q, PathInfo, refs_aggregate
|
||||
from django.db.models.fields.related_lookups import MultiColSource
|
||||
from django.db.models.query_utils import Q, PathInfo, refs_expression
|
||||
from django.db.models.sql.constants import (
|
||||
INNER, LOUTER, ORDER_DIR, ORDER_PATTERN, QUERY_TERMS, SINGLE,
|
||||
)
|
||||
|
|
@ -1006,7 +1007,7 @@ class Query(object):
|
|||
"""
|
||||
lookup_splitted = lookup.split(LOOKUP_SEP)
|
||||
if self._annotations:
|
||||
aggregate, aggregate_lookups = refs_aggregate(lookup_splitted, self.annotations)
|
||||
aggregate, aggregate_lookups = refs_expression(lookup_splitted, self.annotations)
|
||||
if aggregate:
|
||||
return aggregate_lookups, (), aggregate
|
||||
_, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
|
||||
|
|
@ -1157,24 +1158,26 @@ class Query(object):
|
|||
if can_reuse is not None:
|
||||
can_reuse.update(join_list)
|
||||
used_joins = set(used_joins).union(set(join_list))
|
||||
|
||||
# Process the join list to see if we can remove any non-needed joins from
|
||||
# the far end (fewer tables in a query is better).
|
||||
targets, alias, join_list = self.trim_joins(sources, join_list, path)
|
||||
|
||||
if hasattr(field, 'get_lookup_constraint'):
|
||||
# For now foreign keys get special treatment. This should be
|
||||
# refactored when composite fields lands.
|
||||
condition = field.get_lookup_constraint(self.where_class, alias, targets, sources,
|
||||
lookups, value)
|
||||
lookup_type = lookups[-1]
|
||||
else:
|
||||
assert(len(targets) == 1)
|
||||
if hasattr(targets[0], 'as_sql'):
|
||||
# handle Expressions as annotations
|
||||
col = targets[0]
|
||||
if field.is_relation:
|
||||
# No support for transforms for relational fields
|
||||
assert len(lookups) == 1
|
||||
lookup_class = field.get_lookup(lookups[0])
|
||||
# Undo the changes done in setup_joins() if hasattr(final_field, 'field') branch
|
||||
# This hack is needed as long as the field.rel isn't like a real field.
|
||||
if field.get_path_info()[-1].target_fields != sources:
|
||||
target_field = field.rel
|
||||
else:
|
||||
col = targets[0].get_col(alias, field)
|
||||
target_field = field
|
||||
if len(targets) == 1:
|
||||
lhs = targets[0].get_col(alias, target_field)
|
||||
else:
|
||||
lhs = MultiColSource(alias, targets, sources, target_field)
|
||||
condition = lookup_class(lhs, value)
|
||||
lookup_type = lookup_class.lookup_name
|
||||
else:
|
||||
col = targets[0].get_col(alias, field)
|
||||
condition = self.build_lookup(lookups, col, value)
|
||||
lookup_type = condition.lookup_name
|
||||
|
||||
|
|
@ -1284,14 +1287,6 @@ class Query(object):
|
|||
)
|
||||
model = field.model._meta.concrete_model
|
||||
except FieldDoesNotExist:
|
||||
# is it an annotation?
|
||||
if self._annotations and name in self._annotations:
|
||||
field, model = self._annotations[name], None
|
||||
if not field.contains_aggregate:
|
||||
# Local non-relational field.
|
||||
final_field = field
|
||||
targets = (field,)
|
||||
break
|
||||
# We didn't find the current field, so move position back
|
||||
# one step.
|
||||
pos -= 1
|
||||
|
|
@ -1985,7 +1980,7 @@ def is_reverse_o2o(field):
|
|||
A little helper to check if the given field is reverse-o2o. The field is
|
||||
expected to be some sort of relation field or related object.
|
||||
"""
|
||||
return not hasattr(field, 'rel') and field.field.unique
|
||||
return field.is_relation and field.one_to_one and not field.concrete
|
||||
|
||||
|
||||
class JoinPromoter(object):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue