Trim joins from the start of the join path. The candidates for trim are the PathInfos in names_with_path structure that are m2m joins. Also set the select column so the start matches the join. This method is meant to be used for generating the subquery joins &
(self, names_with_path)
| 2694 | return self.extra |
| 2695 | |
| 2696 | def trim_start(self, names_with_path): |
| 2697 | """ |
| 2698 | Trim joins from the start of the join path. The candidates for trim |
| 2699 | are the PathInfos in names_with_path structure that are m2m joins. |
| 2700 | |
| 2701 | Also set the select column so the start matches the join. |
| 2702 | |
| 2703 | This method is meant to be used for generating the subquery joins & |
| 2704 | cols in split_exclude(). |
| 2705 | |
| 2706 | Return a lookup usable for doing outerq.filter(lookup=self) and a |
| 2707 | boolean indicating if the joins in the prefix contain a LEFT OUTER |
| 2708 | join. |
| 2709 | """ |
| 2710 | all_paths = [] |
| 2711 | for _, paths in names_with_path: |
| 2712 | all_paths.extend(paths) |
| 2713 | contains_louter = False |
| 2714 | # Trim and operate only on tables that were generated for |
| 2715 | # the lookup part of the query. That is, avoid trimming |
| 2716 | # joins generated for F() expressions. |
| 2717 | lookup_tables = [ |
| 2718 | t for t in self.alias_map if t in self._lookup_joins or t == self.base_table |
| 2719 | ] |
| 2720 | for trimmed_paths, path in enumerate(all_paths): |
| 2721 | if path.m2m: |
| 2722 | break |
| 2723 | if self.alias_map[lookup_tables[trimmed_paths + 1]].join_type == LOUTER: |
| 2724 | contains_louter = True |
| 2725 | alias = lookup_tables[trimmed_paths] |
| 2726 | self.unref_alias(alias) |
| 2727 | # The path.join_field is a Rel, lets get the other side's field |
| 2728 | join_field = path.join_field.field |
| 2729 | # Build the filter prefix. |
| 2730 | paths_in_prefix = trimmed_paths |
| 2731 | trimmed_prefix = [] |
| 2732 | for name, path in names_with_path: |
| 2733 | if paths_in_prefix - len(path) < 0: |
| 2734 | break |
| 2735 | trimmed_prefix.append(name) |
| 2736 | paths_in_prefix -= len(path) |
| 2737 | trimmed_prefix.append(join_field.foreign_related_fields[0].name) |
| 2738 | trimmed_prefix = LOOKUP_SEP.join(trimmed_prefix) |
| 2739 | # Lets still see if we can trim the first join from the inner query |
| 2740 | # (that is, self). We can't do this for: |
| 2741 | # - LEFT JOINs because we would miss those rows that have nothing on |
| 2742 | # the outer side, |
| 2743 | # - INNER JOINs from filtered relations because we would miss their |
| 2744 | # filters. |
| 2745 | first_join = self.alias_map[lookup_tables[trimmed_paths + 1]] |
| 2746 | if first_join.join_type != LOUTER and not first_join.filtered_relation: |
| 2747 | select_fields = [r[0] for r in join_field.related_fields] |
| 2748 | select_alias = lookup_tables[trimmed_paths + 1] |
| 2749 | self.unref_alias(lookup_tables[trimmed_paths]) |
| 2750 | extra_restriction = join_field.get_extra_restriction( |
| 2751 | None, lookup_tables[trimmed_paths + 1] |
| 2752 | ) |
| 2753 | if extra_restriction: |
no test coverage detected