~ubuntu-branches/ubuntu/precise/python-django/precise-proposed

« back to all changes in this revision

Viewing changes to django/db/models/query.py

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez, Julian Edwards
  • Date: 2012-11-20 16:00:41 UTC
  • Revision ID: package-import@ubuntu.com-20121120160041-140ztibl9h0omz79
Tags: 1.3.1-4ubuntu1.5
[ Julian Edwards ]
* debian/patches:
  - genericipaddressfield.diff: Backport GenericIPAddressField
    from 1.4 (LP: #1081391)
  - prefetch_related.diff: Backport prefetch_related from 1.4 (LP: #1081388)
  - bug15496-base64-multipart-fix.diff: Include fix for upstream bug #15496
    which makes 'Content-Transfer-Encoding: base64: work for multipart
    messages. (LP: #1081392)

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
The main QuerySet implementation. This provides the public API for the ORM.
3
3
"""
4
4
 
5
 
from itertools import izip
 
5
import itertools
6
6
 
7
7
from django.db import connections, router, transaction, IntegrityError
8
8
from django.db.models.aggregates import Aggregate
37
37
        self._iter = None
38
38
        self._sticky_filter = False
39
39
        self._for_write = False
 
40
        self._prefetch_related_lookups = []
 
41
        self._prefetch_done = False
40
42
 
41
43
    ########################
42
44
    # PYTHON MAGIC METHODS #
82
84
                self._result_cache = list(self.iterator())
83
85
        elif self._iter:
84
86
            self._result_cache.extend(self._iter)
 
87
        if self._prefetch_related_lookups and not self._prefetch_done:
 
88
            self._prefetch_related_objects()
85
89
        return len(self._result_cache)
86
90
 
87
91
    def __iter__(self):
 
92
        if self._prefetch_related_lookups and not self._prefetch_done:
 
93
            # We need all the results in order to be able to do the prefetch
 
94
            # in one go. To minimize code duplication, we use the __len__
 
95
            # code path which also forces this, and also does the prefetch
 
96
            len(self)
 
97
 
88
98
        if self._result_cache is None:
89
99
            self._iter = self.iterator()
90
100
            self._result_cache = []
107
117
                self._fill_cache()
108
118
 
109
119
    def __nonzero__(self):
 
120
        if self._prefetch_related_lookups and not self._prefetch_done:
 
121
            # We need all the results in order to be able to do the prefetch
 
122
            # in one go. To minimize code duplication, we use the __len__
 
123
            # code path which also forces this, and also does the prefetch
 
124
            len(self)
 
125
 
110
126
        if self._result_cache is not None:
111
127
            return bool(self._result_cache)
112
128
        try:
496
512
            return self.query.has_results(using=self.db)
497
513
        return bool(self._result_cache)
498
514
 
 
515
    def _prefetch_related_objects(self):
 
516
        # This method can only be called once the result cache has been filled.
 
517
        prefetch_related_objects(self._result_cache, self._prefetch_related_lookups)
 
518
        self._prefetch_done = True
 
519
 
499
520
    ##################################################
500
521
    # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
501
522
    ##################################################
607
628
            obj.query.max_depth = depth
608
629
        return obj
609
630
 
 
631
    def prefetch_related(self, *lookups):
 
632
        """
 
633
        Returns a new QuerySet instance that will prefetch the specified
 
634
        Many-To-One and Many-To-Many related objects when the QuerySet is
 
635
        evaluated.
 
636
 
 
637
        When prefetch_related() is called more than once, the list of lookups to
 
638
        prefetch is appended to. If prefetch_related(None) is called, the
 
639
        the list is cleared.
 
640
        """
 
641
        clone = self._clone()
 
642
        if lookups == (None,):
 
643
            clone._prefetch_related_lookups = []
 
644
        else:
 
645
            clone._prefetch_related_lookups.extend(lookups)
 
646
        return clone
 
647
 
610
648
    def dup_select_related(self, other):
611
649
        """
612
650
        Copies the related selection status from the QuerySet 'other' to the
756
794
            query.filter_is_sticky = True
757
795
        c = klass(model=self.model, query=query, using=self._db)
758
796
        c._for_write = self._for_write
 
797
        c._prefetch_related_lookups = self._prefetch_related_lookups[:]
759
798
        c.__dict__.update(kwargs)
760
799
        if setup and hasattr(c, '_setup_query'):
761
800
            c._setup_query()
1434
1473
    query = sql.InsertQuery(model)
1435
1474
    query.insert_values(values, raw_values)
1436
1475
    return query.get_compiler(using=using).execute_sql(return_id)
 
1476
 
 
1477
 
 
1478
def prefetch_related_objects(result_cache, related_lookups):
 
1479
    """
 
1480
    Helper function for prefetch_related functionality
 
1481
 
 
1482
    Populates prefetched objects caches for a list of results
 
1483
    from a QuerySet
 
1484
    """
 
1485
    from django.db.models.sql.constants import LOOKUP_SEP
 
1486
 
 
1487
    if len(result_cache) == 0:
 
1488
        return # nothing to do
 
1489
 
 
1490
    model = result_cache[0].__class__
 
1491
 
 
1492
    # We need to be able to dynamically add to the list of prefetch_related
 
1493
    # lookups that we look up (see below).  So we need some book keeping to
 
1494
    # ensure we don't do duplicate work.
 
1495
    done_lookups = set() # list of lookups like foo__bar__baz
 
1496
    done_queries = {}    # dictionary of things like 'foo__bar': [results]
 
1497
 
 
1498
    auto_lookups = [] # we add to this as we go through.
 
1499
    followed_descriptors = set() # recursion protection
 
1500
 
 
1501
    all_lookups = itertools.chain(related_lookups, auto_lookups)
 
1502
    for lookup in all_lookups:
 
1503
        if lookup in done_lookups:
 
1504
            # We've done exactly this already, skip the whole thing
 
1505
            continue
 
1506
        done_lookups.add(lookup)
 
1507
 
 
1508
        # Top level, the list of objects to decorate is the the result cache
 
1509
        # from the primary QuerySet. It won't be for deeper levels.
 
1510
        obj_list = result_cache
 
1511
 
 
1512
        attrs = lookup.split(LOOKUP_SEP)
 
1513
        for level, attr in enumerate(attrs):
 
1514
            # Prepare main instances
 
1515
            if len(obj_list) == 0:
 
1516
                break
 
1517
 
 
1518
            good_objects = True
 
1519
            for obj in obj_list:
 
1520
                if not hasattr(obj, '_prefetched_objects_cache'):
 
1521
                    try:
 
1522
                        obj._prefetched_objects_cache = {}
 
1523
                    except AttributeError:
 
1524
                        # Must be in a QuerySet subclass that is not returning
 
1525
                        # Model instances, either in Django or 3rd
 
1526
                        # party. prefetch_related() doesn't make sense, so quit
 
1527
                        # now.
 
1528
                        good_objects = False
 
1529
                        break
 
1530
                else:
 
1531
                    # We already did this list
 
1532
                    break
 
1533
            if not good_objects:
 
1534
                break
 
1535
 
 
1536
            # Descend down tree
 
1537
 
 
1538
            # We assume that objects retrieved are homogenous (which is the premise
 
1539
            # of prefetch_related), so what applies to first object applies to all.
 
1540
            first_obj = obj_list[0]
 
1541
            prefetcher, descriptor, attr_found, is_fetched = get_prefetcher(first_obj, attr)
 
1542
 
 
1543
            if not attr_found:
 
1544
                raise AttributeError("Cannot find '%s' on %s object, '%s' is an invalid "
 
1545
                                     "parameter to prefetch_related()" %
 
1546
                                     (attr, first_obj.__class__.__name__, lookup))
 
1547
 
 
1548
            if level == len(attrs) - 1 and prefetcher is None:
 
1549
                # Last one, this *must* resolve to something that supports
 
1550
                # prefetching, otherwise there is no point adding it and the
 
1551
                # developer asking for it has made a mistake.
 
1552
                raise ValueError("'%s' does not resolve to a item that supports "
 
1553
                                 "prefetching - this is an invalid parameter to "
 
1554
                                 "prefetch_related()." % lookup)
 
1555
 
 
1556
            if prefetcher is not None and not is_fetched:
 
1557
                # Check we didn't do this already
 
1558
                current_lookup = LOOKUP_SEP.join(attrs[0:level+1])
 
1559
                if current_lookup in done_queries:
 
1560
                    obj_list = done_queries[current_lookup]
 
1561
                else:
 
1562
                    obj_list, additional_prl = prefetch_one_level(obj_list, prefetcher, attr)
 
1563
                    # We need to ensure we don't keep adding lookups from the
 
1564
                    # same relationships to stop infinite recursion. So, if we
 
1565
                    # are already on an automatically added lookup, don't add
 
1566
                    # the new lookups from relationships we've seen already.
 
1567
                    if not (lookup in auto_lookups and
 
1568
                            descriptor in followed_descriptors):
 
1569
                        for f in additional_prl:
 
1570
                            new_prl = LOOKUP_SEP.join([current_lookup, f])
 
1571
                            auto_lookups.append(new_prl)
 
1572
                        done_queries[current_lookup] = obj_list
 
1573
                    followed_descriptors.add(descriptor)
 
1574
            else:
 
1575
                # Either a singly related object that has already been fetched
 
1576
                # (e.g. via select_related), or hopefully some other property
 
1577
                # that doesn't support prefetching but needs to be traversed.
 
1578
 
 
1579
                # We replace the current list of parent objects with that list.
 
1580
                obj_list = [getattr(obj, attr) for obj in obj_list]
 
1581
 
 
1582
                # Filter out 'None' so that we can continue with nullable
 
1583
                # relations.
 
1584
                obj_list = [obj for obj in obj_list if obj is not None]
 
1585
 
 
1586
 
 
1587
def get_prefetcher(instance, attr):
 
1588
    """
 
1589
    For the attribute 'attr' on the given instance, finds
 
1590
    an object that has a get_prefetch_query_set().
 
1591
    Returns a 4 tuple containing:
 
1592
    (the object with get_prefetch_query_set (or None),
 
1593
     the descriptor object representing this relationship (or None),
 
1594
     a boolean that is False if the attribute was not found at all,
 
1595
     a boolean that is True if the attribute has already been fetched)
 
1596
    """
 
1597
    prefetcher = None
 
1598
    attr_found = False
 
1599
    is_fetched = False
 
1600
 
 
1601
    # For singly related objects, we have to avoid getting the attribute
 
1602
    # from the object, as this will trigger the query. So we first try
 
1603
    # on the class, in order to get the descriptor object.
 
1604
    rel_obj_descriptor = getattr(instance.__class__, attr, None)
 
1605
    if rel_obj_descriptor is None:
 
1606
        try:
 
1607
            rel_obj = getattr(instance, attr)
 
1608
            attr_found = True
 
1609
        except AttributeError:
 
1610
            pass
 
1611
    else:
 
1612
        attr_found = True
 
1613
        if rel_obj_descriptor:
 
1614
            # singly related object, descriptor object has the
 
1615
            # get_prefetch_query_set() method.
 
1616
            if hasattr(rel_obj_descriptor, 'get_prefetch_query_set'):
 
1617
                prefetcher = rel_obj_descriptor
 
1618
                if rel_obj_descriptor.is_cached(instance):
 
1619
                    is_fetched = True
 
1620
            else:
 
1621
                # descriptor doesn't support prefetching, so we go ahead and get
 
1622
                # the attribute on the instance rather than the class to
 
1623
                # support many related managers
 
1624
                rel_obj = getattr(instance, attr)
 
1625
                if hasattr(rel_obj, 'get_prefetch_query_set'):
 
1626
                    prefetcher = rel_obj
 
1627
    return prefetcher, rel_obj_descriptor, attr_found, is_fetched
 
1628
 
 
1629
 
 
1630
def prefetch_one_level(instances, prefetcher, attname):
 
1631
    """
 
1632
    Helper function for prefetch_related_objects
 
1633
 
 
1634
    Runs prefetches on all instances using the prefetcher object,
 
1635
    assigning results to relevant caches in instance.
 
1636
 
 
1637
    The prefetched objects are returned, along with any additional
 
1638
    prefetches that must be done due to prefetch_related lookups
 
1639
    found from default managers.
 
1640
    """
 
1641
    # prefetcher must have a method get_prefetch_query_set() which takes a list
 
1642
    # of instances, and returns a tuple:
 
1643
 
 
1644
    # (queryset of instances of self.model that are related to passed in instances,
 
1645
    #  callable that gets value to be matched for returned instances,
 
1646
    #  callable that gets value to be matched for passed in instances,
 
1647
    #  boolean that is True for singly related objects,
 
1648
    #  cache name to assign to).
 
1649
 
 
1650
    # The 'values to be matched' must be hashable as they will be used
 
1651
    # in a dictionary.
 
1652
 
 
1653
    rel_qs, rel_obj_attr, instance_attr, single, cache_name =\
 
1654
        prefetcher.get_prefetch_query_set(instances)
 
1655
    # We have to handle the possibility that the default manager itself added
 
1656
    # prefetch_related lookups to the QuerySet we just got back. We don't want to
 
1657
    # trigger the prefetch_related functionality by evaluating the query.
 
1658
    # Rather, we need to merge in the prefetch_related lookups.
 
1659
    additional_prl = getattr(rel_qs, '_prefetch_related_lookups', [])
 
1660
    if additional_prl:
 
1661
        # Don't need to clone because the manager should have given us a fresh
 
1662
        # instance, so we access an internal instead of using public interface
 
1663
        # for performance reasons.
 
1664
        rel_qs._prefetch_related_lookups = []
 
1665
 
 
1666
    all_related_objects = list(rel_qs)
 
1667
 
 
1668
    rel_obj_cache = {}
 
1669
    for rel_obj in all_related_objects:
 
1670
        rel_attr_val = rel_obj_attr(rel_obj)
 
1671
        if rel_attr_val not in rel_obj_cache:
 
1672
            rel_obj_cache[rel_attr_val] = []
 
1673
        rel_obj_cache[rel_attr_val].append(rel_obj)
 
1674
 
 
1675
    for obj in instances:
 
1676
        instance_attr_val = instance_attr(obj)
 
1677
        vals = rel_obj_cache.get(instance_attr_val, [])
 
1678
        if single:
 
1679
            # Need to assign to single cache on instance
 
1680
            if vals:
 
1681
                setattr(obj, cache_name, vals[0])
 
1682
        else:
 
1683
            # Multi, attribute represents a manager with an .all() method that
 
1684
            # returns a QuerySet
 
1685
            qs = getattr(obj, attname).all()
 
1686
            qs._result_cache = vals
 
1687
            # We don't want the individual qs doing prefetch_related now, since we
 
1688
            # have merged this into the current work.
 
1689
            qs._prefetch_done = True
 
1690
            obj._prefetched_objects_cache[cache_name] = qs
 
1691
    return all_related_objects, additional_prl