1 """ |
|
2 40. Tests for select_related() |
|
3 |
|
4 ``select_related()`` follows all relationships and pre-caches any foreign key |
|
5 values so that complex trees can be fetched in a single query. However, this |
|
6 isn't always a good idea, so the ``depth`` argument control how many "levels" |
|
7 the select-related behavior will traverse. |
|
8 """ |
|
9 |
|
10 from django.db import models |
|
11 |
|
12 # Who remembers high school biology? |
|
13 |
|
14 class Domain(models.Model): |
|
15 name = models.CharField(maxlength=50) |
|
16 def __str__(self): |
|
17 return self.name |
|
18 |
|
19 class Kingdom(models.Model): |
|
20 name = models.CharField(maxlength=50) |
|
21 domain = models.ForeignKey(Domain) |
|
22 def __str__(self): |
|
23 return self.name |
|
24 |
|
25 class Phylum(models.Model): |
|
26 name = models.CharField(maxlength=50) |
|
27 kingdom = models.ForeignKey(Kingdom) |
|
28 def __str__(self): |
|
29 return self.name |
|
30 |
|
31 class Klass(models.Model): |
|
32 name = models.CharField(maxlength=50) |
|
33 phylum = models.ForeignKey(Phylum) |
|
34 def __str__(self): |
|
35 return self.name |
|
36 |
|
37 class Order(models.Model): |
|
38 name = models.CharField(maxlength=50) |
|
39 klass = models.ForeignKey(Klass) |
|
40 def __str__(self): |
|
41 return self.name |
|
42 |
|
43 class Family(models.Model): |
|
44 name = models.CharField(maxlength=50) |
|
45 order = models.ForeignKey(Order) |
|
46 def __str__(self): |
|
47 return self.name |
|
48 |
|
49 class Genus(models.Model): |
|
50 name = models.CharField(maxlength=50) |
|
51 family = models.ForeignKey(Family) |
|
52 def __str__(self): |
|
53 return self.name |
|
54 |
|
55 class Species(models.Model): |
|
56 name = models.CharField(maxlength=50) |
|
57 genus = models.ForeignKey(Genus) |
|
58 def __str__(self): |
|
59 return self.name |
|
60 |
|
61 def create_tree(stringtree): |
|
62 """Helper to create a complete tree""" |
|
63 names = stringtree.split() |
|
64 models = [Domain, Kingdom, Phylum, Klass, Order, Family, Genus, Species] |
|
65 assert len(names) == len(models), (names, models) |
|
66 |
|
67 parent = None |
|
68 for name, model in zip(names, models): |
|
69 try: |
|
70 obj = model.objects.get(name=name) |
|
71 except model.DoesNotExist: |
|
72 obj = model(name=name) |
|
73 if parent: |
|
74 setattr(obj, parent.__class__.__name__.lower(), parent) |
|
75 obj.save() |
|
76 parent = obj |
|
77 |
|
78 __test__ = {'API_TESTS':""" |
|
79 |
|
80 # Set up. |
|
81 # The test runner sets settings.DEBUG to False, but we want to gather queries |
|
82 # so we'll set it to True here and reset it at the end of the test suite. |
|
83 >>> from django.conf import settings |
|
84 >>> settings.DEBUG = True |
|
85 |
|
86 >>> create_tree("Eukaryota Animalia Anthropoda Insecta Diptera Drosophilidae Drosophila melanogaster") |
|
87 >>> create_tree("Eukaryota Animalia Chordata Mammalia Primates Hominidae Homo sapiens") |
|
88 >>> create_tree("Eukaryota Plantae Magnoliophyta Magnoliopsida Fabales Fabaceae Pisum sativum") |
|
89 >>> create_tree("Eukaryota Fungi Basidiomycota Homobasidiomycatae Agaricales Amanitacae Amanita muscaria") |
|
90 |
|
91 >>> from django import db |
|
92 |
|
93 # Normally, accessing FKs doesn't fill in related objects: |
|
94 >>> db.reset_queries() |
|
95 >>> fly = Species.objects.get(name="melanogaster") |
|
96 >>> fly.genus.family.order.klass.phylum.kingdom.domain |
|
97 <Domain: Eukaryota> |
|
98 >>> len(db.connection.queries) |
|
99 8 |
|
100 |
|
101 # However, a select_related() call will fill in those related objects without any extra queries: |
|
102 >>> db.reset_queries() |
|
103 >>> person = Species.objects.select_related().get(name="sapiens") |
|
104 >>> person.genus.family.order.klass.phylum.kingdom.domain |
|
105 <Domain: Eukaryota> |
|
106 >>> len(db.connection.queries) |
|
107 1 |
|
108 |
|
109 # select_related() also of course applies to entire lists, not just items. |
|
110 # Without select_related() |
|
111 >>> db.reset_queries() |
|
112 >>> world = Species.objects.all() |
|
113 >>> [o.genus.family for o in world] |
|
114 [<Family: Drosophilidae>, <Family: Hominidae>, <Family: Fabaceae>, <Family: Amanitacae>] |
|
115 >>> len(db.connection.queries) |
|
116 9 |
|
117 |
|
118 # With select_related(): |
|
119 >>> db.reset_queries() |
|
120 >>> world = Species.objects.all().select_related() |
|
121 >>> [o.genus.family for o in world] |
|
122 [<Family: Drosophilidae>, <Family: Hominidae>, <Family: Fabaceae>, <Family: Amanitacae>] |
|
123 >>> len(db.connection.queries) |
|
124 1 |
|
125 |
|
126 # The "depth" argument to select_related() will stop the descent at a particular level: |
|
127 >>> db.reset_queries() |
|
128 >>> pea = Species.objects.select_related(depth=1).get(name="sativum") |
|
129 >>> pea.genus.family.order.klass.phylum.kingdom.domain |
|
130 <Domain: Eukaryota> |
|
131 |
|
132 # Notice: one few query than above because of depth=1 |
|
133 >>> len(db.connection.queries) |
|
134 7 |
|
135 |
|
136 >>> db.reset_queries() |
|
137 >>> pea = Species.objects.select_related(depth=5).get(name="sativum") |
|
138 >>> pea.genus.family.order.klass.phylum.kingdom.domain |
|
139 <Domain: Eukaryota> |
|
140 >>> len(db.connection.queries) |
|
141 3 |
|
142 |
|
143 >>> db.reset_queries() |
|
144 >>> world = Species.objects.all().select_related(depth=2) |
|
145 >>> [o.genus.family.order for o in world] |
|
146 [<Order: Diptera>, <Order: Primates>, <Order: Fabales>, <Order: Agaricales>] |
|
147 >>> len(db.connection.queries) |
|
148 5 |
|
149 |
|
150 # Reset DEBUG to where we found it. |
|
151 >>> settings.DEBUG = False |
|
152 """} |
|