diff options
| author | Nicolas Delaby <ticosax@free.fr> | 2017-09-22 17:53:17 +0200 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2017-09-22 11:53:17 -0400 |
| commit | 01d440fa1e6b5c62acfa8b3fde43dfa1505f93c6 (patch) | |
| tree | 21b1f96ecd0fca636746595bce50eb46abdde880 /django/db/models/sql/datastructures.py | |
| parent | 3f9d85d95cab228fd881ea952c707022e9e3bdf3 (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.py | 42 |
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 + ) |
