1 """ |
|
2 16. Many-to-one relationships that can be null |
|
3 |
|
4 To define a many-to-one relationship that can have a null foreign key, use |
|
5 ``ForeignKey()`` with ``null=True`` . |
|
6 """ |
|
7 |
|
8 from django.db import models |
|
9 |
|
10 class Reporter(models.Model): |
|
11 name = models.CharField(maxlength=30) |
|
12 |
|
13 def __str__(self): |
|
14 return self.name |
|
15 |
|
16 class Article(models.Model): |
|
17 headline = models.CharField(maxlength=100) |
|
18 reporter = models.ForeignKey(Reporter, null=True) |
|
19 |
|
20 class Meta: |
|
21 ordering = ('headline',) |
|
22 |
|
23 def __str__(self): |
|
24 return self.headline |
|
25 |
|
26 __test__ = {'API_TESTS':""" |
|
27 # Create a Reporter. |
|
28 >>> r = Reporter(name='John Smith') |
|
29 >>> r.save() |
|
30 |
|
31 # Create an Article. |
|
32 >>> a = Article(headline="First", reporter=r) |
|
33 >>> a.save() |
|
34 |
|
35 >>> a.reporter.id |
|
36 1 |
|
37 |
|
38 >>> a.reporter |
|
39 <Reporter: John Smith> |
|
40 |
|
41 # Article objects have access to their related Reporter objects. |
|
42 >>> r = a.reporter |
|
43 |
|
44 # Create an Article via the Reporter object. |
|
45 >>> a2 = r.article_set.create(headline="Second") |
|
46 >>> a2 |
|
47 <Article: Second> |
|
48 >>> a2.reporter.id |
|
49 1 |
|
50 |
|
51 # Reporter objects have access to their related Article objects. |
|
52 >>> r.article_set.all() |
|
53 [<Article: First>, <Article: Second>] |
|
54 >>> r.article_set.filter(headline__startswith='Fir') |
|
55 [<Article: First>] |
|
56 >>> r.article_set.count() |
|
57 2 |
|
58 |
|
59 # Create an Article with no Reporter by passing "reporter=None". |
|
60 >>> a3 = Article(headline="Third", reporter=None) |
|
61 >>> a3.save() |
|
62 >>> a3.id |
|
63 3 |
|
64 >>> print a3.reporter |
|
65 None |
|
66 |
|
67 # Need to reget a3 to refresh the cache |
|
68 >>> a3 = Article.objects.get(pk=3) |
|
69 >>> print a3.reporter.id |
|
70 Traceback (most recent call last): |
|
71 ... |
|
72 AttributeError: 'NoneType' object has no attribute 'id' |
|
73 |
|
74 # Accessing an article's 'reporter' attribute returns None |
|
75 # if the reporter is set to None. |
|
76 >>> print a3.reporter |
|
77 None |
|
78 |
|
79 # To retrieve the articles with no reporters set, use "reporter__isnull=True". |
|
80 >>> Article.objects.filter(reporter__isnull=True) |
|
81 [<Article: Third>] |
|
82 |
|
83 # Set the reporter for the Third article |
|
84 >>> r.article_set.add(a3) |
|
85 >>> r.article_set.all() |
|
86 [<Article: First>, <Article: Second>, <Article: Third>] |
|
87 |
|
88 # Remove an article from the set, and check that it was removed. |
|
89 >>> r.article_set.remove(a3) |
|
90 >>> r.article_set.all() |
|
91 [<Article: First>, <Article: Second>] |
|
92 >>> Article.objects.filter(reporter__isnull=True) |
|
93 [<Article: Third>] |
|
94 |
|
95 # Create another article and reporter |
|
96 >>> r2 = Reporter(name='Paul Jones') |
|
97 >>> r2.save() |
|
98 >>> a4 = r2.article_set.create(headline='Fourth') |
|
99 >>> r2.article_set.all() |
|
100 [<Article: Fourth>] |
|
101 |
|
102 # Try to remove a4 from a set it does not belong to |
|
103 >>> r.article_set.remove(a4) |
|
104 Traceback (most recent call last): |
|
105 ... |
|
106 DoesNotExist: <Article: Fourth> is not related to <Reporter: John Smith>. |
|
107 |
|
108 >>> r2.article_set.all() |
|
109 [<Article: Fourth>] |
|
110 |
|
111 # Use descriptor assignment to allocate ForeignKey. Null is legal, so |
|
112 # existing members of set that are not in the assignment set are set null |
|
113 >>> r2.article_set = [a2, a3] |
|
114 >>> r2.article_set.all() |
|
115 [<Article: Second>, <Article: Third>] |
|
116 |
|
117 # Clear the rest of the set |
|
118 >>> r.article_set.clear() |
|
119 >>> r.article_set.all() |
|
120 [] |
|
121 >>> Article.objects.filter(reporter__isnull=True) |
|
122 [<Article: First>, <Article: Fourth>] |
|
123 |
|
124 """} |
|