Django

Code

CookBookPreloadRelated: db.py

File db.py, 3.0 kB (added by akaihola, 2 years ago)

first version

Line 
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])