summaryrefslogtreecommitdiff
path: root/django/db/models/sql/datastructures.py
diff options
context:
space:
mode:
authorNicolas Delaby <ticosax@free.fr>2017-09-22 17:53:17 +0200
committerTim Graham <timograham@gmail.com>2017-09-22 11:53:17 -0400
commit01d440fa1e6b5c62acfa8b3fde43dfa1505f93c6 (patch)
tree21b1f96ecd0fca636746595bce50eb46abdde880 /django/db/models/sql/datastructures.py
parent3f9d85d95cab228fd881ea952c707022e9e3bdf3 (diff)
Fixed #27332 -- Added FilteredRelation API for conditional join (ON clause) support.
Thanks Anssi Kääriäinen for contributing to the patch.
Diffstat (limited to 'django/db/models/sql/datastructures.py')
-rw-r--r--django/db/models/sql/datastructures.py42
1 files changed, 32 insertions, 10 deletions
diff --git a/django/db/models/sql/datastructures.py b/django/db/models/sql/datastructures.py
index 788c2dd669..ab02f65042 100644
--- a/django/db/models/sql/datastructures.py
+++ b/django/db/models/sql/datastructures.py
@@ -41,7 +41,7 @@ class Join:
- relabeled_clone()
"""
def __init__(self, table_name, parent_alias, table_alias, join_type,
- join_field, nullable):
+ join_field, nullable, filtered_relation=None):
# Join table
self.table_name = table_name
self.parent_alias = parent_alias
@@ -56,6 +56,7 @@ class Join:
self.join_field = join_field
# Is this join nullabled?
self.nullable = nullable
+ self.filtered_relation = filtered_relation
def as_sql(self, compiler, connection):
"""
@@ -85,7 +86,11 @@ class Join:
extra_sql, extra_params = compiler.compile(extra_cond)
join_conditions.append('(%s)' % extra_sql)
params.extend(extra_params)
-
+ if self.filtered_relation:
+ extra_sql, extra_params = compiler.compile(self.filtered_relation)
+ if extra_sql:
+ join_conditions.append('(%s)' % extra_sql)
+ params.extend(extra_params)
if not join_conditions:
# This might be a rel on the other end of an actual declared field.
declared_field = getattr(self.join_field, 'field', self.join_field)
@@ -101,18 +106,27 @@ class Join:
def relabeled_clone(self, change_map):
new_parent_alias = change_map.get(self.parent_alias, self.parent_alias)
new_table_alias = change_map.get(self.table_alias, self.table_alias)
+ if self.filtered_relation is not None:
+ filtered_relation = self.filtered_relation.clone()
+ filtered_relation.path = [change_map.get(p, p) for p in self.filtered_relation.path]
+ else:
+ filtered_relation = None
return self.__class__(
self.table_name, new_parent_alias, new_table_alias, self.join_type,
- self.join_field, self.nullable)
+ self.join_field, self.nullable, filtered_relation=filtered_relation,
+ )
+
+ def equals(self, other, with_filtered_relation):
+ return (
+ isinstance(other, self.__class__) and
+ self.table_name == other.table_name and
+ self.parent_alias == other.parent_alias and
+ self.join_field == other.join_field and
+ (not with_filtered_relation or self.filtered_relation == other.filtered_relation)
+ )
def __eq__(self, other):
- if isinstance(other, self.__class__):
- return (
- self.table_name == other.table_name and
- self.parent_alias == other.parent_alias and
- self.join_field == other.join_field
- )
- return False
+ return self.equals(other, with_filtered_relation=True)
def demote(self):
new = self.relabeled_clone({})
@@ -134,6 +148,7 @@ class BaseTable:
"""
join_type = None
parent_alias = None
+ filtered_relation = None
def __init__(self, table_name, alias):
self.table_name = table_name
@@ -146,3 +161,10 @@ class BaseTable:
def relabeled_clone(self, change_map):
return self.__class__(self.table_name, change_map.get(self.table_alias, self.table_alias))
+
+ def equals(self, other, with_filtered_relation):
+ return (
+ isinstance(self, other.__class__) and
+ self.table_name == other.table_name and
+ self.table_alias == other.table_alias
+ )