1 | #!/usr/bin/python
|
---|
2 | # -*- encoding: utf-8 -*-
|
---|
3 |
|
---|
4 | ##
|
---|
5 | ## ambidjangolib/db.py
|
---|
6 | ## Created on Wed Apr 5 23:26:18 2006
|
---|
7 | ## by Antti Kaihola <akaihola@ambitone.com>
|
---|
8 | ##
|
---|
9 | ## Copyright (C) 2006 Antti Kaihola
|
---|
10 | ## This program is free software; you can redistribute it and/or modify
|
---|
11 | ## it under the terms of the GNU General Public License as published by
|
---|
12 | ## the Free Software Foundation; either version 2 of the License, or
|
---|
13 | ## (at your option) any later version.
|
---|
14 | ##
|
---|
15 | ## This program is distributed in the hope that it will be useful,
|
---|
16 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
17 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
18 | ## GNU General Public License for more details.
|
---|
19 | ##
|
---|
20 | ## You should have received a copy of the GNU General Public License
|
---|
21 | ## along with this program; if not, write to the Free Software
|
---|
22 | ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
---|
23 | ##
|
---|
24 |
|
---|
25 | def preload_related(objects, model, *related):
|
---|
26 | """
|
---|
27 | Given a queryset of objects, retrieves related objects and stores
|
---|
28 | them as lists into attributes of the original objects.
|
---|
29 |
|
---|
30 | See http://code.djangoproject.com/wiki/CookBookPreloadRelated for
|
---|
31 | more information.
|
---|
32 |
|
---|
33 | Example:
|
---|
34 | >>> users = User.objects.filter(username__startswith='a')
|
---|
35 | >>> preload_related(users,
|
---|
36 | ... User,
|
---|
37 | ... (UserProperty.objects, Property.objects, 'properties'),
|
---|
38 | ... (UserAlias.objects , Alias.objects , 'aliases' ))
|
---|
39 | >>> users[0].properties
|
---|
40 | [<a list containing Property objects>]
|
---|
41 | >>> users[0].aliases
|
---|
42 | [<a list containing Alias objects>]
|
---|
43 | """
|
---|
44 |
|
---|
45 | # store the list of object IDs locally for performance
|
---|
46 | object_ids = [obj._get_pk_val() for obj in objects]
|
---|
47 |
|
---|
48 | cached_objects = {}
|
---|
49 |
|
---|
50 | for (m2m_set, rel_set, attr) in related:
|
---|
51 |
|
---|
52 | # name of ForeignKey field referring to main objects
|
---|
53 | leftfield = [f.name for f in m2m_set.model._meta.fields
|
---|
54 | if f.rel and f.rel.to._meta is model._meta][0]
|
---|
55 |
|
---|
56 | # name of ForeignKey field referring to related objects
|
---|
57 | rightfield = [f.name for f in m2m_set.model._meta.fields
|
---|
58 | if f.rel and f.rel.to._meta is rel_set.model._meta][0]
|
---|
59 |
|
---|
60 | # query all m2m rows which refer to one of the main objects
|
---|
61 | # already in memory
|
---|
62 | criteria = {'%s__in' % leftfield: object_ids}
|
---|
63 | cached_objects[attr] = {
|
---|
64 | 'field' : rightfield,
|
---|
65 | 'objects': m2m_set.filter(**criteria).select_related(True)}
|
---|
66 |
|
---|
67 | for obj in objects:
|
---|
68 | # store retrieved related objects into corresponding main
|
---|
69 | # objects
|
---|
70 | for attr, cachedict in cached_objects.iteritems():
|
---|
71 | rightfield = cachedict['field']
|
---|
72 | event_objects = [getattr(cached_obj, rightfield)
|
---|
73 | for cached_obj in cached_objects[attr]['objects']
|
---|
74 | if getattr(cached_obj, leftfield) == obj]
|
---|
75 | setattr(obj, attr, event_objects)
|
---|
76 | setattr(obj, attr+'_ids', [eo._get_pk_val() for eo in event_objects])
|
---|