diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 72948f9..d940c97 100644
a
|
b
|
class SQLCompiler(object):
|
456 | 456 | """ |
457 | 457 | if not alias: |
458 | 458 | alias = self.query.get_initial_alias() |
459 | | field, target, opts, joins, _, _ = self.query.setup_joins(pieces, |
| 459 | field, target, opts, joins, _, _, _ = self.query.setup_joins(pieces, |
460 | 460 | opts, alias, False) |
461 | 461 | alias = joins[-1] |
462 | 462 | col = target.column |
diff --git a/django/db/models/sql/expressions.py b/django/db/models/sql/expressions.py
index 1bbf742..af1ed63 100644
a
|
b
|
class SQLEvaluator(object):
|
44 | 44 | self.cols[node] = query.aggregate_select[node.name] |
45 | 45 | else: |
46 | 46 | try: |
47 | | field, source, opts, join_list, last, _ = query.setup_joins( |
| 47 | field, source, opts, join_list, last, _, _ = query.setup_joins( |
48 | 48 | field_list, query.get_meta(), |
49 | 49 | query.get_initial_alias(), False) |
50 | 50 | col, _, join_list = query.trim_joins(source, join_list, last, False) |
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index a78df34..630a270 100644
a
|
b
|
class Query(object):
|
700 | 700 | return True |
701 | 701 | return False |
702 | 702 | |
| 703 | def demote_alias(self, alias): |
| 704 | """ |
| 705 | Demotes the join type of an alias to an inner join. |
| 706 | """ |
| 707 | data = list(self.alias_map[alias]) |
| 708 | data[JOIN_TYPE] = self.INNER |
| 709 | self.alias_map[alias] = tuple(data) |
| 710 | |
703 | 711 | def promote_alias_chain(self, chain, must_promote=False): |
704 | 712 | """ |
705 | 713 | Walks along a chain of aliases, promoting the first nullable join and |
… |
… |
class Query(object):
|
1007 | 1015 | # - this is an annotation over a model field |
1008 | 1016 | # then we need to explore the joins that are required. |
1009 | 1017 | |
1010 | | field, source, opts, join_list, last, _ = self.setup_joins( |
| 1018 | field, source, opts, join_list, last, _, _ = self.setup_joins( |
1011 | 1019 | field_list, opts, self.get_initial_alias(), False) |
1012 | 1020 | |
1013 | 1021 | # Process the join chain to see if it can be trimmed |
… |
… |
class Query(object):
|
1119 | 1127 | allow_many = trim or not negate |
1120 | 1128 | |
1121 | 1129 | try: |
1122 | | field, target, opts, join_list, last, extra_filters = self.setup_joins( |
| 1130 | field, target, opts, join_list, last, extra_filters, allow_trim_join = self.setup_joins( |
1123 | 1131 | parts, opts, alias, True, allow_many, allow_explicit_fk=True, |
1124 | 1132 | can_reuse=can_reuse, negate=negate, |
1125 | 1133 | process_extras=process_extras) |
… |
… |
class Query(object):
|
1139 | 1147 | self.promote_alias_chain(join_list) |
1140 | 1148 | join_promote = True |
1141 | 1149 | |
| 1150 | # If we have a one2one or many2one field, we can trim the left outer |
| 1151 | # join from the end of a list of joins. |
| 1152 | # In order to do this, we convert alias join type back to INNER and |
| 1153 | # trim_joins later will do the strip for us. |
| 1154 | if allow_trim_join and field.rel: |
| 1155 | self.demote_alias(join_list[-1]) |
| 1156 | |
1142 | 1157 | # Process the join list to see if we can remove any inner joins from |
1143 | 1158 | # the far end (fewer tables in a query is better). |
1144 | 1159 | nonnull_comparison = (lookup_type == 'isnull' and value is False) |
… |
… |
class Query(object):
|
1295 | 1310 | dupe_set = set() |
1296 | 1311 | exclusions = set() |
1297 | 1312 | extra_filters = [] |
| 1313 | allow_trim_join = True |
1298 | 1314 | int_alias = None |
1299 | 1315 | for pos, name in enumerate(names): |
1300 | 1316 | if int_alias is not None: |
… |
… |
class Query(object):
|
1318 | 1334 | raise FieldError("Cannot resolve keyword %r into field. " |
1319 | 1335 | "Choices are: %s" % (name, ", ".join(names))) |
1320 | 1336 | |
| 1337 | # presence of indirect field in the filter requires |
| 1338 | # left outer join for isnull |
| 1339 | if not direct and allow_trim_join: |
| 1340 | allow_trim_join = False |
| 1341 | |
1321 | 1342 | if not allow_many and (m2m or not direct): |
1322 | 1343 | for alias in joins: |
1323 | 1344 | self.unref_alias(alias) |
… |
… |
class Query(object):
|
1359 | 1380 | extra_filters.extend(field.extra_filters(names, pos, negate)) |
1360 | 1381 | if direct: |
1361 | 1382 | if m2m: |
| 1383 | # null query on m2mfield requires outer join |
| 1384 | allow_trim_join = False |
1362 | 1385 | # Many-to-many field defined on the current model. |
1363 | 1386 | if cached_data: |
1364 | 1387 | (table1, from_col1, to_col1, table2, from_col2, |
… |
… |
class Query(object):
|
1479 | 1502 | else: |
1480 | 1503 | raise FieldError("Join on field %r not permitted." % name) |
1481 | 1504 | |
1482 | | return field, target, opts, joins, last, extra_filters |
| 1505 | return field, target, opts, joins, last, extra_filters, allow_trim_join |
1483 | 1506 | |
1484 | 1507 | def trim_joins(self, target, join_list, last, trim, nonnull_check=False): |
1485 | 1508 | """ |
… |
… |
class Query(object):
|
1648 | 1671 | |
1649 | 1672 | try: |
1650 | 1673 | for name in field_names: |
1651 | | field, target, u2, joins, u3, u4 = self.setup_joins( |
| 1674 | field, target, u2, joins, u3, u4, allow_trim_join = self.setup_joins( |
1652 | 1675 | name.split(LOOKUP_SEP), opts, alias, False, allow_m2m, |
1653 | 1676 | True) |
1654 | 1677 | final_alias = joins[-1] |
… |
… |
class Query(object):
|
1930 | 1953 | """ |
1931 | 1954 | opts = self.model._meta |
1932 | 1955 | alias = self.get_initial_alias() |
1933 | | field, col, opts, joins, last, extra = self.setup_joins( |
| 1956 | field, col, opts, joins, last, extra, allow_trim_join = self.setup_joins( |
1934 | 1957 | start.split(LOOKUP_SEP), opts, alias, False) |
1935 | 1958 | select_col = self.alias_map[joins[1]][LHS_JOIN_COL] |
1936 | 1959 | select_alias = alias |