~ubuntu-branches/debian/squeeze/python-django/squeeze

« back to all changes in this revision

Viewing changes to tests/modeltests/select_related/models.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb, Chris Lamb, David Spreen, Sandro Tosi
  • Date: 2008-11-19 21:31:00 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20081119213100-gp0lqhxl1qxa6dgl
Tags: 1.0.2-1
[ Chris Lamb ]
* New upstream bugfix release. Closes: #505783
* Add myself to Uploaders with ACK from Brett.

[ David Spreen ]
* Remove python-pysqlite2 from Recommends because Python 2.5 includes
  sqlite library used by Django. Closes: 497886

[ Sandro Tosi ]
* debian/control
  - switch Vcs-Browser field to viewsvn

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""
2
 
41. 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(max_length=50)
16
 
    def __unicode__(self):
17
 
        return self.name
18
 
 
19
 
class Kingdom(models.Model):
20
 
    name = models.CharField(max_length=50)
21
 
    domain = models.ForeignKey(Domain)
22
 
    def __unicode__(self):
23
 
        return self.name
24
 
 
25
 
class Phylum(models.Model):
26
 
    name = models.CharField(max_length=50)
27
 
    kingdom = models.ForeignKey(Kingdom)
28
 
    def __unicode__(self):
29
 
        return self.name
30
 
 
31
 
class Klass(models.Model):
32
 
    name = models.CharField(max_length=50)
33
 
    phylum = models.ForeignKey(Phylum)
34
 
    def __unicode__(self):
35
 
        return self.name
36
 
 
37
 
class Order(models.Model):
38
 
    name = models.CharField(max_length=50)
39
 
    klass = models.ForeignKey(Klass)
40
 
    def __unicode__(self):
41
 
        return self.name
42
 
 
43
 
class Family(models.Model):
44
 
    name = models.CharField(max_length=50)
45
 
    order = models.ForeignKey(Order)
46
 
    def __unicode__(self):
47
 
        return self.name
48
 
 
49
 
class Genus(models.Model):
50
 
    name = models.CharField(max_length=50)
51
 
    family = models.ForeignKey(Family)
52
 
    def __unicode__(self):
53
 
        return self.name
54
 
 
55
 
class Species(models.Model):
56
 
    name = models.CharField(max_length=50)
57
 
    genus = models.ForeignKey(Genus)
58
 
    def __unicode__(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(depth=10).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 fewer queries 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
 
>>> s = Species.objects.all().select_related(depth=1).extra(select={'a': 'select_related_species.id + 10'})[0]
151
 
>>> s.id + 10 == s.a
152
 
True
153
 
 
154
 
# The optional fields passed to select_related() control which related models
155
 
# we pull in. This allows for smaller queries and can act as an alternative
156
 
# (or, in addition to) the depth parameter.
157
 
 
158
 
# In the next two cases, we explicitly say to select the 'genus' and
159
 
# 'genus.family' models, leading to the same number of queries as before.
160
 
>>> db.reset_queries()
161
 
>>> world = Species.objects.select_related('genus__family')
162
 
>>> [o.genus.family for o in world]
163
 
[<Family: Drosophilidae>, <Family: Hominidae>, <Family: Fabaceae>, <Family: Amanitacae>]
164
 
>>> len(db.connection.queries)
165
 
1
166
 
 
167
 
>>> db.reset_queries()
168
 
>>> world = Species.objects.filter(genus__name='Amanita').select_related('genus__family')
169
 
>>> [o.genus.family.order for o in world]
170
 
[<Order: Agaricales>]
171
 
>>> len(db.connection.queries)
172
 
2
173
 
 
174
 
>>> db.reset_queries()
175
 
>>> Species.objects.all().select_related('genus__family__order').order_by('id')[0:1].get().genus.family.order.name
176
 
u'Diptera'
177
 
>>> len(db.connection.queries)
178
 
1
179
 
 
180
 
# Specifying both "depth" and fields is an error.
181
 
>>> Species.objects.select_related('genus__family__order', depth=4)
182
 
Traceback (most recent call last):
183
 
...
184
 
TypeError: Cannot pass both "depth" and fields to select_related()
185
 
 
186
 
# Reset DEBUG to where we found it.
187
 
>>> settings.DEBUG = False
188
 
"""}
189