MCPcopy
hub / github.com/django/django / combine

Method combine

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

Merge the 'rhs' query into the current one (with any 'rhs' effects being applied *after* (that is, "to the right of") anything in the current query. 'rhs' is not modified during a call to this function. The 'connector' parameter describes how to connect filters from

(self, rhs, connector)

Source from the content-addressed store, hash-verified

698 return "\n".join(compiler.explain_query())
699
700 def combine(self, rhs, connector):
701 """
702 Merge the 'rhs' query into the current one (with any 'rhs' effects
703 being applied *after* (that is, "to the right of") anything in the
704 current query. 'rhs' is not modified during a call to this function.
705
706 The 'connector' parameter describes how to connect filters from the
707 'rhs' query.
708 """
709 if self.model != rhs.model:
710 raise TypeError("Cannot combine queries on two different base models.")
711 if self.is_sliced:
712 raise TypeError("Cannot combine queries once a slice has been taken.")
713 if self.distinct != rhs.distinct:
714 raise TypeError("Cannot combine a unique query with a non-unique query.")
715 if self.distinct_fields != rhs.distinct_fields:
716 raise TypeError("Cannot combine queries with different distinct fields.")
717
718 # If lhs and rhs shares the same alias prefix, it is possible to have
719 # conflicting alias changes like T4 -> T5, T5 -> T6, which might end up
720 # as T4 -> T6 while combining two querysets. To prevent this, change an
721 # alias prefix of the rhs and update current aliases accordingly,
722 # except if the alias is the base table since it must be present in the
723 # query on both sides.
724 initial_alias = self.get_initial_alias()
725 rhs = rhs.clone()
726 rhs.bump_prefix(self, exclude={initial_alias})
727
728 # Work out how to relabel the rhs aliases, if necessary.
729 change_map = {}
730 conjunction = connector == AND
731
732 # Determine which existing joins can be reused. When combining the
733 # query with AND we must recreate all joins for m2m filters. When
734 # combining with OR we can reuse joins. The reason is that in AND
735 # case a single row can't fulfill a condition like:
736 # revrel__col=1 & revrel__col=2
737 # But, there might be two different related rows matching this
738 # condition. In OR case a single True is enough, so single row is
739 # enough, too.
740 #
741 # Note that we will be creating duplicate joins for non-m2m joins in
742 # the AND case. The results will be correct but this creates too many
743 # joins. This is something that could be fixed later on.
744 reuse = set() if conjunction else set(self.alias_map)
745 joinpromoter = JoinPromoter(connector, 2, False)
746 joinpromoter.add_votes(
747 j for j in self.alias_map if self.alias_map[j].join_type == INNER
748 )
749 rhs_votes = set()
750 # Now, add the joins from rhs query into the new query (skipping base
751 # table).
752 rhs_tables = list(rhs.alias_map)[1:]
753 for alias in rhs_tables:
754 join = rhs.alias_map[alias]
755 # If the left side of the join was already relabeled, use the
756 # updated alias.
757 join = join.relabeled_clone(change_map)

Callers 12

_get_latest_lastmodFunction · 0.80
rfc2822_dateFunction · 0.80
rfc3339_dateFunction · 0.80
rMethod · 0.80
UMethod · 0.80
_make_date_lookup_argMethod · 0.80
compressMethod · 0.80
__and__Method · 0.80
__or__Method · 0.80
__xor__Method · 0.80
setUpTestDataMethod · 0.80

Calls 15

get_initial_aliasMethod · 0.95
add_votesMethod · 0.95
joinMethod · 0.95
unref_aliasMethod · 0.95
update_join_typesMethod · 0.95
set_selectMethod · 0.95
set_extra_maskMethod · 0.95
JoinPromoterClass · 0.85
bump_prefixMethod · 0.80
discardMethod · 0.80
relabel_aliasesMethod · 0.80
cloneMethod · 0.45

Tested by 1

setUpTestDataMethod · 0.64