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)
1478
def prefetch_related_objects(result_cache, related_lookups):
1480
Helper function for prefetch_related functionality
1482
Populates prefetched objects caches for a list of results
1485
from django.db.models.sql.constants import LOOKUP_SEP
1487
if len(result_cache) == 0:
1488
return # nothing to do
1490
model = result_cache[0].__class__
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]
1498
auto_lookups = [] # we add to this as we go through.
1499
followed_descriptors = set() # recursion protection
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
1506
done_lookups.add(lookup)
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
1512
attrs = lookup.split(LOOKUP_SEP)
1513
for level, attr in enumerate(attrs):
1514
# Prepare main instances
1515
if len(obj_list) == 0:
1519
for obj in obj_list:
1520
if not hasattr(obj, '_prefetched_objects_cache'):
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
1528
good_objects = False
1531
# We already did this list
1533
if not good_objects:
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)
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))
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)
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]
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)
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.
1579
# We replace the current list of parent objects with that list.
1580
obj_list = [getattr(obj, attr) for obj in obj_list]
1582
# Filter out 'None' so that we can continue with nullable
1584
obj_list = [obj for obj in obj_list if obj is not None]
1587
def get_prefetcher(instance, attr):
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)
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:
1607
rel_obj = getattr(instance, attr)
1609
except AttributeError:
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):
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
1630
def prefetch_one_level(instances, prefetcher, attname):
1632
Helper function for prefetch_related_objects
1634
Runs prefetches on all instances using the prefetcher object,
1635
assigning results to relevant caches in instance.
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.
1641
# prefetcher must have a method get_prefetch_query_set() which takes a list
1642
# of instances, and returns a tuple:
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).
1650
# The 'values to be matched' must be hashable as they will be used
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', [])
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 = []
1666
all_related_objects = list(rel_qs)
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)
1675
for obj in instances:
1676
instance_attr_val = instance_attr(obj)
1677
vals = rel_obj_cache.get(instance_attr_val, [])
1679
# Need to assign to single cache on instance
1681
setattr(obj, cache_name, vals[0])
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