1 """ |
|
2 10. One-to-one relationships |
|
3 |
|
4 To define a one-to-one relationship, use ``OneToOneField()``. |
|
5 |
|
6 In this example, a ``Place`` optionally can be a ``Restaurant``. |
|
7 """ |
|
8 |
|
9 from django.db import models |
|
10 |
|
11 class Place(models.Model): |
|
12 name = models.CharField(maxlength=50) |
|
13 address = models.CharField(maxlength=80) |
|
14 |
|
15 def __str__(self): |
|
16 return "%s the place" % self.name |
|
17 |
|
18 class Restaurant(models.Model): |
|
19 place = models.OneToOneField(Place) |
|
20 serves_hot_dogs = models.BooleanField() |
|
21 serves_pizza = models.BooleanField() |
|
22 |
|
23 def __str__(self): |
|
24 return "%s the restaurant" % self.place.name |
|
25 |
|
26 class Waiter(models.Model): |
|
27 restaurant = models.ForeignKey(Restaurant) |
|
28 name = models.CharField(maxlength=50) |
|
29 |
|
30 def __str__(self): |
|
31 return "%s the waiter at %s" % (self.name, self.restaurant) |
|
32 |
|
33 class ManualPrimaryKey(models.Model): |
|
34 primary_key = models.CharField(maxlength=10, primary_key=True) |
|
35 name = models.CharField(maxlength = 50) |
|
36 |
|
37 class RelatedModel(models.Model): |
|
38 link = models.OneToOneField(ManualPrimaryKey) |
|
39 name = models.CharField(maxlength = 50) |
|
40 |
|
41 __test__ = {'API_TESTS':""" |
|
42 # Create a couple of Places. |
|
43 >>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton') |
|
44 >>> p1.save() |
|
45 >>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland') |
|
46 >>> p2.save() |
|
47 |
|
48 # Create a Restaurant. Pass the ID of the "parent" object as this object's ID. |
|
49 >>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False) |
|
50 >>> r.save() |
|
51 |
|
52 # A Restaurant can access its place. |
|
53 >>> r.place |
|
54 <Place: Demon Dogs the place> |
|
55 |
|
56 # A Place can access its restaurant, if available. |
|
57 >>> p1.restaurant |
|
58 <Restaurant: Demon Dogs the restaurant> |
|
59 |
|
60 # p2 doesn't have an associated restaurant. |
|
61 >>> p2.restaurant |
|
62 Traceback (most recent call last): |
|
63 ... |
|
64 DoesNotExist: Restaurant matching query does not exist. |
|
65 |
|
66 # Set the place using assignment notation. Because place is the primary key on Restaurant, |
|
67 # the save will create a new restaurant |
|
68 >>> r.place = p2 |
|
69 >>> r.save() |
|
70 >>> p2.restaurant |
|
71 <Restaurant: Ace Hardware the restaurant> |
|
72 >>> r.place |
|
73 <Place: Ace Hardware the place> |
|
74 |
|
75 # Set the place back again, using assignment in the reverse direction |
|
76 # Need to reget restaurant object first, because the reverse set |
|
77 # can't update the existing restaurant instance |
|
78 >>> p1.restaurant = r |
|
79 >>> r.save() |
|
80 >>> p1.restaurant |
|
81 <Restaurant: Demon Dogs the restaurant> |
|
82 |
|
83 >>> r = Restaurant.objects.get(pk=1) |
|
84 >>> r.place |
|
85 <Place: Demon Dogs the place> |
|
86 |
|
87 # Restaurant.objects.all() just returns the Restaurants, not the Places. |
|
88 # Note that there are two restaurants - Ace Hardware the Restaurant was created |
|
89 # in the call to r.place = p2. This means there are multiple restaurants referencing |
|
90 # a single place... |
|
91 >>> Restaurant.objects.all() |
|
92 [<Restaurant: Demon Dogs the restaurant>, <Restaurant: Ace Hardware the restaurant>] |
|
93 |
|
94 # Place.objects.all() returns all Places, regardless of whether they have |
|
95 # Restaurants. |
|
96 >>> Place.objects.order_by('name') |
|
97 [<Place: Ace Hardware the place>, <Place: Demon Dogs the place>] |
|
98 |
|
99 >>> Restaurant.objects.get(place__id__exact=1) |
|
100 <Restaurant: Demon Dogs the restaurant> |
|
101 >>> Restaurant.objects.get(pk=1) |
|
102 <Restaurant: Demon Dogs the restaurant> |
|
103 >>> Restaurant.objects.get(place__exact=1) |
|
104 <Restaurant: Demon Dogs the restaurant> |
|
105 >>> Restaurant.objects.get(place__exact=p1) |
|
106 <Restaurant: Demon Dogs the restaurant> |
|
107 >>> Restaurant.objects.get(place=1) |
|
108 <Restaurant: Demon Dogs the restaurant> |
|
109 >>> Restaurant.objects.get(place=p1) |
|
110 <Restaurant: Demon Dogs the restaurant> |
|
111 >>> Restaurant.objects.get(place__pk=1) |
|
112 <Restaurant: Demon Dogs the restaurant> |
|
113 >>> Restaurant.objects.get(place__name__startswith="Demon") |
|
114 <Restaurant: Demon Dogs the restaurant> |
|
115 |
|
116 >>> Place.objects.get(id__exact=1) |
|
117 <Place: Demon Dogs the place> |
|
118 >>> Place.objects.get(pk=1) |
|
119 <Place: Demon Dogs the place> |
|
120 >>> Place.objects.get(restaurant__place__exact=1) |
|
121 <Place: Demon Dogs the place> |
|
122 >>> Place.objects.get(restaurant__place__exact=p1) |
|
123 <Place: Demon Dogs the place> |
|
124 >>> Place.objects.get(restaurant__pk=1) |
|
125 <Place: Demon Dogs the place> |
|
126 >>> Place.objects.get(restaurant=1) |
|
127 <Place: Demon Dogs the place> |
|
128 >>> Place.objects.get(restaurant=r) |
|
129 <Place: Demon Dogs the place> |
|
130 >>> Place.objects.get(restaurant__exact=1) |
|
131 <Place: Demon Dogs the place> |
|
132 >>> Place.objects.get(restaurant__exact=r) |
|
133 <Place: Demon Dogs the place> |
|
134 |
|
135 # Add a Waiter to the Restaurant. |
|
136 >>> w = r.waiter_set.create(name='Joe') |
|
137 >>> w.save() |
|
138 >>> w |
|
139 <Waiter: Joe the waiter at Demon Dogs the restaurant> |
|
140 |
|
141 # Query the waiters |
|
142 >>> Waiter.objects.filter(restaurant__place__pk=1) |
|
143 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] |
|
144 >>> Waiter.objects.filter(restaurant__place__exact=1) |
|
145 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] |
|
146 >>> Waiter.objects.filter(restaurant__place__exact=p1) |
|
147 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] |
|
148 >>> Waiter.objects.filter(restaurant__pk=1) |
|
149 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] |
|
150 >>> Waiter.objects.filter(id__exact=1) |
|
151 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] |
|
152 >>> Waiter.objects.filter(pk=1) |
|
153 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] |
|
154 >>> Waiter.objects.filter(restaurant=1) |
|
155 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] |
|
156 >>> Waiter.objects.filter(restaurant=r) |
|
157 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] |
|
158 |
|
159 # Delete the restaurant; the waiter should also be removed |
|
160 >>> r = Restaurant.objects.get(pk=1) |
|
161 >>> r.delete() |
|
162 |
|
163 # One-to-one fields still work if you create your own primary key |
|
164 >>> o1 = ManualPrimaryKey(primary_key="abc123", name="primary") |
|
165 >>> o1.save() |
|
166 >>> o2 = RelatedModel(link=o1, name="secondary") |
|
167 >>> o2.save() |
|
168 """} |
|