From nobody Mon Sep 17 00:00:00 2001
From: Michael Radziej <mir@noris.de>
Date: Fri Mar 9 20:32:31 2007 +0100
Subject: [PATCH] outer for or
Refreshed patch outer-for-or.
(Base: f59ca82d7e4a6d495bda443b56b49a2e00678cc0)
(Last: 500c179ee84b8984680d7e7a3b21adec7cd8fb51)
---
django/db/models/query.py | 69 ++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 68 insertions(+), 1 deletions(-)
base c2e6175cdf58493d0c1325be40d41a33c8105919
last 8118dc0da5a118e665f725529c4a8ed3a665e247
diff --git a/django/db/models/query.py b/django/db/models/query.py
index c6f1c1d6b1d35127aedcb1f19f70a635ad0a651c..864783a87223896de0d38bd88748bdd87b16639d 100644
a
|
b
|
class EmptyQuerySet(QuerySet):
|
703 | 703 | |
704 | 704 | class QOperator(object): |
705 | 705 | "Base class for QAnd and QOr" |
| 706 | underneath_an_or = False # used to track ORs |
| 707 | checked_or = False |
| 708 | |
| 709 | def search_for_or(self): |
| 710 | " Returns true if an or exists beneath this Q operator. " |
| 711 | if type(self) == QOr: |
| 712 | return True |
| 713 | |
| 714 | for val in self.args: |
| 715 | if val.search_for_or(): |
| 716 | return True |
| 717 | |
| 718 | return False # there was no OR below this. |
| 719 | |
| 720 | def set_or_found(self, or_value): |
| 721 | if self.checked_or: |
| 722 | return |
| 723 | |
| 724 | self.underneath_an_or = or_value |
| 725 | self.checked_or = True |
| 726 | |
| 727 | for val in self.args: |
| 728 | val.set_or_found(or_value) # set for all the children |
| 729 | |
706 | 730 | def __init__(self, *args): |
707 | 731 | self.args = args |
708 | 732 | |
709 | 733 | def get_sql(self, opts): |
| 734 | |
| 735 | if not self.checked_or: |
| 736 | found_an_or = self.search_for_or() |
| 737 | self.set_or_found(found_an_or) |
| 738 | |
| 739 | # now that we've finished building the query |
| 740 | self.checked_or = False |
| 741 | |
710 | 742 | joins, where, params = SortedDict(), [], [] |
711 | 743 | for val in self.args: |
712 | 744 | try: |
… |
… |
class QOr(QOperator):
|
751 | 783 | |
752 | 784 | class Q(object): |
753 | 785 | "Encapsulates queries as objects that can be combined logically." |
| 786 | underneath_an_or = False |
| 787 | checked_or = False |
| 788 | outer_join = 'LEFT OUTER JOIN' |
| 789 | inner_join = 'INNER JOIN' |
| 790 | |
754 | 791 | def __init__(self, **kwargs): |
755 | 792 | self.kwargs = kwargs |
756 | 793 | |
… |
… |
class Q(object):
|
760 | 797 | def __or__(self, other): |
761 | 798 | return QOr(self, other) |
762 | 799 | |
| 800 | def search_for_or(self): |
| 801 | ' Returns false, since there are no OR Qs below. ' |
| 802 | return False |
| 803 | |
| 804 | def set_or_found(self, or_found): |
| 805 | """ Set whether or not we have an OR above us. """ |
| 806 | if not self.checked_or: |
| 807 | self.underneath_an_or = or_found |
| 808 | self.checked_or = True # we checked for an OR |
| 809 | |
763 | 810 | def get_sql(self, opts): |
764 | | return parse_lookup(self.kwargs.items(), opts) |
| 811 | # we will check to see if it's an OR, and change the join |
| 812 | # based upon that |
| 813 | |
| 814 | if self.underneath_an_or: |
| 815 | join_text = self.outer_join |
| 816 | else: |
| 817 | join_text = self.inner_join |
| 818 | |
| 819 | joins, where, params = parse_lookup(self.kwargs.items(), opts) |
| 820 | |
| 821 | joins2 = {} |
| 822 | for item, key in joins.items(): |
| 823 | # now we will fix the joins dictionary with |
| 824 | # the new type of join |
| 825 | joins2[item] = (key[0], join_text, key[2]) |
| 826 | |
| 827 | # now that we've done creating the query, |
| 828 | # it's best that we let ourselves search again |
| 829 | self.checked_or = False |
| 830 | |
| 831 | return joins2, where, params |
765 | 832 | |
766 | 833 | class QNot(Q): |
767 | 834 | "Encapsulates NOT (...) queries as objects" |