Django

Code

root/django/trunk/tests/modeltests/many_to_one/models.py

Revision 8325, 11.1 kB (checked in by gwilson, 3 weeks ago)

Fixed a couple typos in the modeltests' descriptions and made use of ReST inline literal markup for code snippets.

  • Property svn:eol-style set to native
Line 
1 """
2 4. Many-to-one relationships
3
4 To define a many-to-one relationship, use ``ForeignKey()``.
5 """
6
7 from django.db import models
8
9 class Reporter(models.Model):
10     first_name = models.CharField(max_length=30)
11     last_name = models.CharField(max_length=30)
12     email = models.EmailField()
13
14     def __unicode__(self):
15         return u"%s %s" % (self.first_name, self.last_name)
16
17 class Article(models.Model):
18     headline = models.CharField(max_length=100)
19     pub_date = models.DateField()
20     reporter = models.ForeignKey(Reporter)
21
22     def __unicode__(self):
23         return self.headline
24
25     class Meta:
26         ordering = ('headline',)
27
28 __test__ = {'API_TESTS':"""
29 # Create a few Reporters.
30 >>> r = Reporter(first_name='John', last_name='Smith', email='john@example.com')
31 >>> r.save()
32
33 >>> r2 = Reporter(first_name='Paul', last_name='Jones', email='paul@example.com')
34 >>> r2.save()
35
36 # Create an Article.
37 >>> from datetime import datetime
38 >>> a = Article(id=None, headline="This is a test", pub_date=datetime(2005, 7, 27), reporter=r)
39 >>> a.save()
40
41 >>> a.reporter.id
42 1
43
44 >>> a.reporter
45 <Reporter: John Smith>
46
47 # Article objects have access to their related Reporter objects.
48 >>> r = a.reporter
49
50 # These are strings instead of unicode strings because that's what was used in
51 # the creation of this reporter (and we haven't refreshed the data from the
52 # database, which always returns unicode strings).
53 >>> r.first_name, r.last_name
54 ('John', 'Smith')
55
56 # Create an Article via the Reporter object.
57 >>> new_article = r.article_set.create(headline="John's second story", pub_date=datetime(2005, 7, 29))
58 >>> new_article
59 <Article: John's second story>
60 >>> new_article.reporter.id
61 1
62
63 # Create a new article, and add it to the article set.
64 >>> new_article2 = Article(headline="Paul's story", pub_date=datetime(2006, 1, 17))
65 >>> r.article_set.add(new_article2)
66 >>> new_article2.reporter.id
67 1
68 >>> r.article_set.all()
69 [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
70
71 # Add the same article to a different article set - check that it moves.
72 >>> r2.article_set.add(new_article2)
73 >>> new_article2.reporter.id
74 2
75 >>> r.article_set.all()
76 [<Article: John's second story>, <Article: This is a test>]
77 >>> r2.article_set.all()
78 [<Article: Paul's story>]
79
80 # Assign the article to the reporter directly using the descriptor
81 >>> new_article2.reporter = r
82 >>> new_article2.save()
83 >>> new_article2.reporter
84 <Reporter: John Smith>
85 >>> new_article2.reporter.id
86 1
87 >>> r.article_set.all()
88 [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
89 >>> r2.article_set.all()
90 []
91
92 # Set the article back again using set descriptor.
93 >>> r2.article_set = [new_article, new_article2]
94 >>> r.article_set.all()
95 [<Article: This is a test>]
96 >>> r2.article_set.all()
97 [<Article: John's second story>, <Article: Paul's story>]
98
99 # Funny case - assignment notation can only go so far; because the
100 # ForeignKey cannot be null, existing members of the set must remain
101 >>> r.article_set = [new_article]
102 >>> r.article_set.all()
103 [<Article: John's second story>, <Article: This is a test>]
104 >>> r2.article_set.all()
105 [<Article: Paul's story>]
106
107 # Reporter cannot be null - there should not be a clear or remove method
108 >>> hasattr(r2.article_set, 'remove')
109 False
110 >>> hasattr(r2.article_set, 'clear')
111 False
112
113 # Reporter objects have access to their related Article objects.
114 >>> r.article_set.all()
115 [<Article: John's second story>, <Article: This is a test>]
116
117 >>> r.article_set.filter(headline__startswith='This')
118 [<Article: This is a test>]
119
120 >>> r.article_set.count()
121 2
122
123 >>> r2.article_set.count()
124 1
125
126 # Get articles by id
127 >>> Article.objects.filter(id__exact=1)
128 [<Article: This is a test>]
129 >>> Article.objects.filter(pk=1)
130 [<Article: This is a test>]
131
132 # Query on an article property
133 >>> Article.objects.filter(headline__startswith='This')
134 [<Article: This is a test>]
135
136 # The API automatically follows relationships as far as you need.
137 # Use double underscores to separate relationships.
138 # This works as many levels deep as you want. There's no limit.
139 # Find all Articles for any Reporter whose first name is "John".
140 >>> Article.objects.filter(reporter__first_name__exact='John')
141 [<Article: John's second story>, <Article: This is a test>]
142
143 # Check that implied __exact also works
144 >>> Article.objects.filter(reporter__first_name='John')
145 [<Article: John's second story>, <Article: This is a test>]
146
147 # Query twice over the related field.
148 >>> Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith')
149 [<Article: John's second story>, <Article: This is a test>]
150
151 # The underlying query only makes one join when a related table is referenced twice.
152 >>> queryset = Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith')
153 >>> sql = queryset.query.as_sql()[0]
154 >>> sql.count('INNER JOIN')
155 1
156
157 # The automatically joined table has a predictable name.
158 >>> Article.objects.filter(reporter__first_name__exact='John').extra(where=["many_to_one_reporter.last_name='Smith'"])
159 [<Article: John's second story>, <Article: This is a test>]
160
161 # And should work fine with the unicode that comes out of
162 # forms.Form.cleaned_data
163 >>> Article.objects.filter(reporter__first_name__exact='John').extra(where=["many_to_one_reporter.last_name='%s'" % u'Smith'])
164 [<Article: John's second story>, <Article: This is a test>]
165
166 # Find all Articles for the Reporter whose ID is 1.
167 # Use direct ID check, pk check, and object comparison
168 >>> Article.objects.filter(reporter__id__exact=1)
169 [<Article: John's second story>, <Article: This is a test>]
170 >>> Article.objects.filter(reporter__pk=1)
171 [<Article: John's second story>, <Article: This is a test>]
172 >>> Article.objects.filter(reporter=1)
173 [<Article: John's second story>, <Article: This is a test>]
174 >>> Article.objects.filter(reporter=r)
175 [<Article: John's second story>, <Article: This is a test>]
176
177 >>> Article.objects.filter(reporter__in=[1,2]).distinct()
178 [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
179 >>> Article.objects.filter(reporter__in=[r,r2]).distinct()
180 [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
181
182 # You can also use a queryset instead of a literal list of instances.
183 # The queryset must be reduced to a list of values using values(),
184 # then converted into a query
185 >>> Article.objects.filter(reporter__in=Reporter.objects.filter(first_name='John').values('pk').query).distinct()
186 [<Article: John's second story>, <Article: This is a test>]
187
188 # You need two underscores between "reporter" and "id" -- not one.
189 >>> Article.objects.filter(reporter_id__exact=1)
190 Traceback (most recent call last):
191     ...
192 FieldError: Cannot resolve keyword 'reporter_id' into field. Choices are: headline, id, pub_date, reporter
193
194 # You need to specify a comparison clause
195 >>> Article.objects.filter(reporter_id=1)
196 Traceback (most recent call last):
197     ...
198 FieldError: Cannot resolve keyword 'reporter_id' into field. Choices are: headline, id, pub_date, reporter
199
200 # You can also instantiate an Article by passing
201 # the Reporter's ID instead of a Reporter object.
202 >>> a3 = Article(id=None, headline="This is a test", pub_date=datetime(2005, 7, 27), reporter_id=r.id)
203 >>> a3.save()
204 >>> a3.reporter.id
205 1
206 >>> a3.reporter
207 <Reporter: John Smith>
208
209 # Similarly, the reporter ID can be a string.
210 >>> a4 = Article(id=None, headline="This is a test", pub_date=datetime(2005, 7, 27), reporter_id="1")
211 >>> a4.save()
212 >>> a4.reporter
213 <Reporter: John Smith>
214
215 # Reporters can be queried
216 >>> Reporter.objects.filter(id__exact=1)
217 [<Reporter: John Smith>]
218 >>> Reporter.objects.filter(pk=1)
219 [<Reporter: John Smith>]
220 >>> Reporter.objects.filter(first_name__startswith='John')
221 [<Reporter: John Smith>]
222
223 # Reporters can query in opposite direction of ForeignKey definition
224 >>> Reporter.objects.filter(article__id__exact=1)
225 [<Reporter: John Smith>]
226 >>> Reporter.objects.filter(article__pk=1)
227 [<Reporter: John Smith>]
228 >>> Reporter.objects.filter(article=1)
229 [<Reporter: John Smith>]
230 >>> Reporter.objects.filter(article=a)
231 [<Reporter: John Smith>]
232
233 >>> Reporter.objects.filter(article__in=[1,4]).distinct()
234 [<Reporter: John Smith>]
235 >>> Reporter.objects.filter(article__in=[1,a3]).distinct()
236 [<Reporter: John Smith>]
237 >>> Reporter.objects.filter(article__in=[a,a3]).distinct()
238 [<Reporter: John Smith>]
239
240 >>> Reporter.objects.filter(article__headline__startswith='This')
241 [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]
242 >>> Reporter.objects.filter(article__headline__startswith='This').distinct()
243 [<Reporter: John Smith>]
244
245 # Counting in the opposite direction works in conjunction with distinct()
246 >>> Reporter.objects.filter(article__headline__startswith='This').count()
247 3
248 >>> Reporter.objects.filter(article__headline__startswith='This').distinct().count()
249 1
250
251 # Queries can go round in circles.
252 >>> Reporter.objects.filter(article__reporter__first_name__startswith='John')
253 [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]
254 >>> Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct()
255 [<Reporter: John Smith>]
256 >>> Reporter.objects.filter(article__reporter__exact=r).distinct()
257 [<Reporter: John Smith>]
258
259 # Check that implied __exact also works.
260 >>> Reporter.objects.filter(article__reporter=r).distinct()
261 [<Reporter: John Smith>]
262
263 # It's possible to use values() calls across many-to-one relations. (Note, too, that we clear the ordering here so as not to drag the 'headline' field into the columns being used to determine uniqueness.)
264 >>> d = {'reporter__first_name': u'John', 'reporter__last_name': u'Smith'}
265 >>> list(Article.objects.filter(reporter=r).distinct().order_by().values('reporter__first_name', 'reporter__last_name')) == [d]
266 True
267
268 # If you delete a reporter, his articles will be deleted.
269 >>> Article.objects.all()
270 [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>, <Article: This is a test>, <Article: This is a test>]
271 >>> Reporter.objects.order_by('first_name')
272 [<Reporter: John Smith>, <Reporter: Paul Jones>]
273 >>> r2.delete()
274 >>> Article.objects.all()
275 [<Article: John's second story>, <Article: This is a test>, <Article: This is a test>, <Article: This is a test>]
276 >>> Reporter.objects.order_by('first_name')
277 [<Reporter: John Smith>]
278
279 # You can delete using a JOIN in the query.
280 >>> Reporter.objects.filter(article__headline__startswith='This').delete()
281 >>> Reporter.objects.all()
282 []
283 >>> Article.objects.all()
284 []
285
286 # Check that Article.objects.select_related().dates() works properly when
287 # there are multiple Articles with the same date but different foreign-key
288 # objects (Reporters).
289 >>> r1 = Reporter.objects.create(first_name='Mike', last_name='Royko', email='royko@suntimes.com')
290 >>> r2 = Reporter.objects.create(first_name='John', last_name='Kass', email='jkass@tribune.com')
291 >>> a1 = Article.objects.create(headline='First', pub_date=datetime(1980, 4, 23), reporter=r1)
292 >>> a2 = Article.objects.create(headline='Second', pub_date=datetime(1980, 4, 23), reporter=r2)
293 >>> Article.objects.select_related().dates('pub_date', 'day')
294 [datetime.datetime(1980, 4, 23, 0, 0)]
295 >>> Article.objects.select_related().dates('pub_date', 'month')
296 [datetime.datetime(1980, 4, 1, 0, 0)]
297 >>> Article.objects.select_related().dates('pub_date', 'year')
298 [datetime.datetime(1980, 1, 1, 0, 0)]
299 """}
Note: See TracBrowser for help on using the browser.