|
11
|
1 |
from django.contrib.contenttypes.models import ContentType |
|
|
2 |
|
|
|
3 |
def fetch_content_objects(tagged_items, select_related_for=None): |
|
|
4 |
""" |
|
|
5 |
Retrieves ``ContentType`` and content objects for the given list of |
|
|
6 |
``TaggedItems``, grouping the retrieval of content objects by model |
|
|
7 |
type to reduce the number of queries executed. |
|
|
8 |
|
|
|
9 |
This results in ``number_of_content_types + 1`` queries rather than |
|
|
10 |
the ``number_of_tagged_items * 2`` queries you'd get by iterating |
|
|
11 |
over the list and accessing each item's ``object`` attribute. |
|
|
12 |
|
|
|
13 |
A ``select_related_for`` argument can be used to specify a list of |
|
|
14 |
of model names (corresponding to the ``model`` field of a |
|
|
15 |
``ContentType``) for which ``select_related`` should be used when |
|
|
16 |
retrieving model instances. |
|
|
17 |
""" |
|
|
18 |
if select_related_for is None: select_related_for = [] |
|
|
19 |
|
|
|
20 |
# Group content object pks by their content type pks |
|
|
21 |
objects = {} |
|
|
22 |
for item in tagged_items: |
|
|
23 |
objects.setdefault(item.content_type_id, []).append(item.object_id) |
|
|
24 |
|
|
|
25 |
# Retrieve content types and content objects in bulk |
|
|
26 |
content_types = ContentType._default_manager.in_bulk(objects.keys()) |
|
|
27 |
for content_type_pk, object_pks in objects.iteritems(): |
|
|
28 |
model = content_types[content_type_pk].model_class() |
|
|
29 |
if content_types[content_type_pk].model in select_related_for: |
|
|
30 |
objects[content_type_pk] = model._default_manager.select_related().in_bulk(object_pks) |
|
|
31 |
else: |
|
|
32 |
objects[content_type_pk] = model._default_manager.in_bulk(object_pks) |
|
|
33 |
|
|
|
34 |
# Set content types and content objects in the appropriate cache |
|
|
35 |
# attributes, so accessing the 'content_type' and 'object' |
|
|
36 |
# attributes on each tagged item won't result in further database |
|
|
37 |
# hits. |
|
|
38 |
for item in tagged_items: |
|
|
39 |
item._object_cache = objects[item.content_type_id][item.object_id] |
|
|
40 |
item._content_type_cache = content_types[item.content_type_id] |