Changeset 7317
- Timestamp:
- 03/19/08 06:02:22 (8 months ago)
- Files:
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/queryset-refactor/django/db/models/sql/query.py
r7288 r7317 810 810 811 811 def add_filter(self, filter_expr, connector=AND, negate=False, trim=False, 812 merge_negated=False):812 single_filter=False): 813 813 """ 814 814 Add a single filter to the query. The 'filter_expr' is a pair: … … 819 819 constructing nested queries). 820 820 821 If 'merge_negated' is True, this negated filter will be merged with the 822 existing negated where node (if it exists). This is used when 823 constructing an exclude filter from combined subfilters. 821 If 'single_filter' is True, we are processing a component of a 822 multi-component filter (e.g. filter(Q1, Q2)). 824 823 """ 825 824 arg, value = filter_expr … … 850 849 try: 851 850 field, target, opts, join_list, last = self.setup_joins(parts, opts, 852 alias, (connector == AND) , allow_many)851 alias, (connector == AND) and not single_filter, allow_many) 853 852 except MultiJoin, e: 854 853 self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level])) … … 918 917 919 918 entry = (alias, col, field, lookup_type, value) 920 if merge_negated:919 if negate and single_filter: 921 920 # This case is when we're doing the Q2 filter in exclude(Q1, Q2). 922 921 # It's different from exclude(Q1).exclude(Q2). … … 958 957 subtree = False 959 958 connector = AND 960 merge= False959 internal = False 961 960 for child in q_object.children: 962 961 if isinstance(child, Node): … … 966 965 else: 967 966 self.add_filter(child, connector, q_object.negated, 968 merge_negated=merge)969 merge = q_object.negated967 single_filter=internal) 968 internal = True 970 969 connector = q_object.connector 971 970 if subtree: django/branches/queryset-refactor/docs/db-api.txt
r7285 r7317 1560 1560 1561 1561 Lookups that span relationships 1562 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1562 ------------------------------- 1563 1563 1564 1564 Django offers a powerful and intuitive way to "follow" relationships in … … 1583 1583 Blog.objects.filter(entry__headline__contains='Lennon') 1584 1584 1585 Spanning multi-valued relationships 1586 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1587 1588 **New in Django development version** 1589 1590 .. note:: 1591 This is an experimental API and subject to change prior to 1592 queryset-refactor being merged into trunk. 1593 1594 When you are filtering an object based on a ``ManyToManyField`` or a reverse 1595 ``ForeignKeyField``, there are two different sorts of filter you may be 1596 interested in. Consider the ``Blog``/``Entry`` relationship (``Blog`` to 1597 ``Entry`` is a one-to-many relation). We might be interested in finding blogs 1598 that have an entry which has both *"Lennon"* in the headline and was published 1599 today. Or we might want to find blogs that have an entry with *"Lennon"* in 1600 the headline as well as an entry that was published today. Since there are 1601 multiple entries associated with a single ``Blog``, both of these queries are 1602 possible and make sense in some situations. 1603 1604 The same type of situation arises with a ``ManyToManyField``. For example, if 1605 an ``Entry`` has a ``ManyToManyField`` called ``tags``, we might want to find 1606 entries linked to tags called *"music"* and *"bands"* or we might want an 1607 entry that contains a tag with a name of *"music"* and a status of *"public"*. 1608 1609 To handle both of these situations, Django has a consistent way of processing 1610 ``filter()`` and ``exclude()`` calls. Everything inside a single ``filter()`` 1611 call is applied simultaneously to filter out items matching all those 1612 requirements. Successive ``filter()`` calls further restrict the set of 1613 objects, but for multi-valued relations, they apply to any object linked to 1614 the primary model, not necessarily those objects that were selected by an 1615 earlier ``filter()`` call. 1616 1617 That may sound a bit confusing, so hopefully an example will clarify. To 1618 select all blogs that contains entries with *"Lennon"* in the headline and 1619 were published today, we would write:: 1620 1621 Blog.objects.filter(entry__headline__contains='Lennon', 1622 entry__pub_date=datetime.date.today()) 1623 1624 To select all blogs that contain an entry with *"Lennon"* in the headline 1625 **as well as** an entry that was published today, we would write:: 1626 1627 Blog.objects.filter(entry__headline__contains='Lennon').filter( 1628 entry__pub_date=datetime.date.today()) 1629 1630 In this second example, the first filter restricted the queryset to all those 1631 blogs linked to that particular type of entry. The second filter restricted 1632 the set of blogs *further* to those that are also linked to the second type of 1633 entry. The entries select by the second filter may or may not be the same as 1634 the entries in the first filter. We are filtering the ``Blog`` items with each 1635 filter statement, not the ``Entry`` items. 1636 1637 All of this behaviour also applies to ``exclude()``: all the conditions in a 1638 single ``exclude()`` statement apply to a single instance (if those conditions 1639 are talking about the same multi-valued relation). Conditions in subsequent 1640 ``filter()`` or ``exclude()`` calls that refer to the same relation may end up 1641 filtering on different linked objects. 1642 1585 1643 Escaping percent signs and underscores in LIKE statements 1586 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1644 --------------------------------------------------------- 1587 1645 1588 1646 The field lookups that equate to ``LIKE`` SQL statements (``iexact``, django/branches/queryset-refactor/tests/regressiontests/queries/models.py
r7286 r7317 211 211 >>> Item.objects.filter(Q(tags=t1)).order_by('name') 212 212 [<Item: one>, <Item: two>] 213 >>> Item.objects.filter(Q(tags=t1) & Q(tags=t2))214 [<Item: one>]215 213 >>> Item.objects.filter(Q(tags=t1)).filter(Q(tags=t2)) 216 214 [<Item: one>] 215 216 Each filter call is processed "at once" against a single table, so this is 217 different from the previous example as it tries to find tags that are two 218 things at once (rather than two tags). 219 >>> Item.objects.filter(Q(tags=t1) & Q(tags=t2)) 220 [] 221 222 >>> qs = Author.objects.filter(ranking__rank=2, ranking__id=rank1.id) 223 >>> list(qs) 224 [<Author: a2>] 225 >>> qs.query.count_active_tables() 226 2 227 >>> qs = Author.objects.filter(ranking__rank=2).filter(ranking__id=rank1.id) 228 >>> qs.query.count_active_tables() 229 3 217 230 218 231 Bug #4464
