Ticket #17605: patch_17605.diff
File patch_17605.diff, 23.8 KB (added by , 13 years ago) |
---|
-
new file docs/topics/db/examples/many_to_many.txt
diff --git a/docs/topics/db/examples/many_to_many.txt b/docs/topics/db/examples/many_to_many.txt new file mode 100644 index 0000000..412493b
- + 1 ########################## 2 Many-to-many relationships 3 ########################## 4 5 To define a many-to-many relationship, use :ref:`ref-manytomany`. 6 7 In this example, an ``Article`` can be published in multiple ``Publication`` 8 objects, and a ``Publication`` has multiple ``Article`` objects:: 9 10 from django.db import models 11 12 class Publication(models.Model): 13 title = models.CharField(max_length=30) 14 15 def __unicode__(self): 16 return self.title 17 18 class Meta: 19 ordering = ('title',) 20 21 class Article(models.Model): 22 headline = models.CharField(max_length=100) 23 publications = models.ManyToManyField(Publication) 24 25 def __unicode__(self): 26 return self.headline 27 28 class Meta: 29 ordering = ('headline',) 30 31 What follows are examples of operations that can be performed using the Python 32 API facilities:: 33 34 >>> # Create a couple of Publications. 35 >>> p1 = Publication(title='The Python Journal') 36 >>> p1.save() 37 >>> p2 = Publication(title='Science News') 38 >>> p2.save() 39 >>> p3 = Publication(title='Science Weekly') 40 >>> p3.save() 41 42 # Create an Article. 43 >>> a1 = Article(headline='Django lets you build Web apps easily') 44 45 # You can't associate it with a Publication until it's been saved. 46 >>> a1.publications.add(p1) 47 Traceback (most recent call last): 48 ... 49 ValueError: 'Article' instance needs to have a primary key value before a many-to-many relationship can be used. 50 51 # Save it! 52 >>> a1.save() 53 54 # Associate the Article with a Publication. 55 >>> a1.publications.add(p1) 56 57 # Create another Article, and set it to appear in both 58 # Publications. 59 >>> a2 = Article(headline='NASA uses Python') 60 >>> a2.save() 61 >>> a2.publications.add(p1, p2) 62 >>> a2.publications.add(p3) 63 64 # Adding a second time is OK 65 >>> a2.publications.add(p3) 66 67 # Adding an object of the wrong type raises TypeError 68 >>> a2.publications.add(a1) 69 Traceback (most recent call last): 70 ... 71 TypeError: 'Publication' instance expected 72 73 # Add a Publication directly via publications.add by using 74 # keyword arguments. 75 >>> new_publication = a2.publications.create(title='Highlights for Children') 76 77 # Article objects have access to their related Publication 78 # objects. 79 >>> a1.publications.all() 80 [<Publication: The Python Journal>] 81 >>> a2.publications.all() 82 [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>] 83 84 # Publication objects have access to their related Article objects. 85 >>> p2.article_set.all() 86 [<Article: NASA uses Python>] 87 >>> p1.article_set.all() 88 [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] 89 >>> Publication.objects.get(id=4).article_set.all() 90 [<Article: NASA uses Python>] 91 92 Many-to-many relationships can be queried using :ref:`lookups across relationships <lookups-that-span-relationships>`:: 93 94 >>> Article.objects.filter(publications__id__exact=1) 95 [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] 96 >>> Article.objects.filter(publications=p1) 97 [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] 98 99 >>> Article.objects.filter(publications__title__startswith="Science") 100 [<Article: NASA uses Python>, <Article: NASA uses Python>] 101 102 >>> Article.objects.filter(publications__title__startswith="Science").distinct() 103 [<Article: NASA uses Python>] 104 105 # The count() function respects distinct() as well. 106 >>> Article.objects.filter(publications__title__startswith="Science").count() 107 2 108 109 >>> Article.objects.filter(publications__title__startswith="Science").distinct().count() 110 1 111 112 >>> Article.objects.filter(publications__in=[1,2]).distinct() 113 [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] 114 >>> Article.objects.filter(publications__in=[p1,p2]).distinct() 115 [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] 116 117 Reverse m2m queries are supported (i.e., starting at the table 118 that doesn't have a ManyToManyField). 119 120 :: 121 122 >>> Publication.objects.filter(id__exact=1) 123 [<Publication: The Python Journal>] 124 >>> Publication.objects.filter(pk=1) 125 [<Publication: The Python Journal>] 126 127 >>> Publication.objects.filter(article__headline__startswith="NASA") 128 [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>] 129 130 >>> Publication.objects.filter(article__pk=1) 131 [<Publication: The Python Journal>] 132 >>> Publication.objects.filter(article=1) 133 [<Publication: The Python Journal>] 134 >>> Publication.objects.filter(article=a1) 135 [<Publication: The Python Journal>] 136 137 >>> Publication.objects.filter(article__in=[1,2]).distinct() 138 [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>] 139 >>> Publication.objects.filter(article__in=[a1,a2]).distinct() 140 [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>] 141 142 Excluding a related item works as you would expect, too 143 (although the SQL involved is a little complex). 144 145 :: 146 147 >>> Article.objects.exclude(publications=p2) 148 [<Article: Django lets you build Web apps easily>] 149 150 If we delete an object from one end of the M2M relation, its related objects 151 won't be able to access it. 152 153 :: 154 155 >>> p1.delete() 156 >>> Publication.objects.all() 157 [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>] 158 >>> a1 = Article.objects.get(pk=1) 159 >>> a1.publications.all() 160 [] 161 162 >>> a2.delete() 163 >>> Article.objects.all() 164 [<Article: Django lets you build Web apps easily>] 165 >>> p2.article_set.all() 166 [] 167 168 169 170 # Adding via the 'other' end of an m2m 171 >>> a4 = Article(headline='NASA finds intelligent life on Earth') 172 >>> a4.save() 173 >>> p2.article_set.add(a4) 174 >>> p2.article_set.all() 175 [<Article: NASA finds intelligent life on Earth>] 176 >>> a4.publications.all() 177 [<Publication: Science News>] 178 179 # Adding via the other end using keywords 180 >>> new_article = p2.article_set.create(headline='Oxygen-free diet works wonders') 181 >>> p2.article_set.all() 182 [<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>] 183 >>> a5 = p2.article_set.all()[1] 184 >>> a5.publications.all() 185 [<Publication: Science News>] 186 187 # Removing publication from an article: 188 >>> a4.publications.remove(p2) 189 >>> p2.article_set.all() 190 [<Article: Oxygen-free diet works wonders>] 191 >>> a4.publications.all() 192 [] 193 194 # And from the other end 195 >>> p2.article_set.remove(a5) 196 >>> p2.article_set.all() 197 [] 198 >>> a5.publications.all() 199 [] 200 201 Relation sets can be assigned or cleared. Assignment clears any previously 202 existing set members. 203 204 :: 205 206 >>> a4.publications.all() 207 [<Publication: Science News>] 208 >>> a4.publications = [p3] 209 >>> a4.publications.all() 210 [<Publication: Science Weekly>] 211 212 >>> p2.article_set.clear() 213 >>> p2.article_set.all() 214 [] 215 216 # And you can clear from the other end 217 >>> p2.article_set.add(a4, a5) 218 >>> p2.article_set.all() 219 [<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>] 220 >>> a4.publications.all() 221 [<Publication: Science News>, <Publication: Science Weekly>] 222 >>> a4.publications.clear() 223 >>> a4.publications.all() 224 [] 225 >>> p2.article_set.all() 226 [<Article: Oxygen-free diet works wonders>] 227 228 # Recreate the article and Publication we have deleted. 229 >>> p1 = Publication(title='The Python Journal') 230 >>> p1.save() 231 >>> a2 = Article(headline='NASA uses Python') 232 >>> a2.save() 233 >>> a2.publications.add(p1, p2, p3) 234 235 # Bulk delete some Publications - references to deleted 236 # publications should go 237 >>> Publication.objects.filter(title__startswith='Science').delete() 238 >>> Publication.objects.all() 239 [<Publication: Highlights for Children>, <Publication: The Python Journal>] 240 >>> Article.objects.all() 241 [<Article: Django lets you build Web apps easily>, <Article: NASA finds intelligent life on Earth>, <Article: NASA uses Python>, <Article: Oxygen-free diet works wonders>] 242 >>> a2.publications.all() 243 [<Publication: The Python Journal>] 244 245 # Bulk delete some articles - references to deleted objects 246 # should go 247 >>> q = Article.objects.filter(headline__startswith='Django') 248 >>> print q 249 [<Article: Django lets you build Web apps easily>] 250 >>> q.delete() 251 252 # After the delete, the QuerySet cache needs to be cleared, and 253 # the referenced objects should be gone 254 >>> print q 255 [] 256 >>> p1.article_set.all() 257 [<Article: NASA uses Python>] 258 259 # An alternate to calling clear() is to assign the empty set 260 >>> p1.article_set = [] 261 >>> p1.article_set.all() 262 [] 263 264 >>> a2.publications = [p1, new_publication] 265 >>> a2.publications.all() 266 [<Publication: Highlights for Children>, <Publication: The Python Journal>] 267 >>> a2.publications = [] 268 >>> a2.publications.all() 269 [] -
new file docs/topics/db/examples/many_to_one.txt
diff --git a/docs/topics/db/examples/many_to_one.txt b/docs/topics/db/examples/many_to_one.txt new file mode 100644 index 0000000..c9786a8
- + 1 ######################### 2 Many-to-one relationships 3 ######################### 4 5 To define a many-to-one relationship, use :class:`django.db.models.ForeignKey`. 6 7 :: 8 9 from django.db import models 10 11 class Reporter(models.Model): 12 first_name = models.CharField(max_length=30) 13 last_name = models.CharField(max_length=30) 14 email = models.EmailField() 15 16 def __unicode__(self): 17 return u"%s %s" % (self.first_name, self.last_name) 18 19 class Article(models.Model): 20 headline = models.CharField(max_length=100) 21 pub_date = models.DateField() 22 reporter = models.ForeignKey(Reporter) 23 24 def __unicode__(self): 25 return self.headline 26 27 class Meta: 28 ordering = ('headline',) 29 30 What follows are examples of operations that can be performed using the Python 31 API facilities:: 32 33 >>> # Create a few Reporters. 34 >>> r = Reporter(first_name='John', last_name='Smith', email='john@example.com') 35 >>> r.save() 36 37 >>> r2 = Reporter(first_name='Paul', last_name='Jones', email='paul@example.com') 38 >>> r2.save() 39 40 # Create an Article. 41 >>> from datetime import datetime 42 >>> a = Article(id=None, headline="This is a test", pub_date=datetime(2005, 7, 27), reporter=r) 43 >>> a.save() 44 45 >>> a.reporter 46 <Reporter: John Smith> 47 48 # Article objects have access to their related Reporter objects. 49 >>> r = a.reporter 50 51 # These are strings instead of unicode strings because that's what was used 52 # in the creation of this reporter (and we haven't refreshed the data from 53 # the database, which always returns unicode strings). 54 >>> r.first_name, r.last_name 55 ('John', 'Smith') 56 57 # Create an Article via the Reporter object. 58 >>> new_article = r.article_set.create(headline="John's second story", pub_date=datetime(2005, 7, 29)) 59 >>> new_article 60 <Article: John's second story> 61 >>> new_article.reporter 62 <Reporter: John Smith> 63 64 # Create a new article, and add it to the article set. 65 >>> new_article2 = Article(headline="Paul's story", pub_date=datetime(2006, 1, 17)) 66 >>> r.article_set.add(new_article2) 67 >>> new_article2.reporter 68 <Reporter: John Smith> 69 >>> r.article_set.all() 70 [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>] 71 72 # Add the same article to a different article set. 73 >>> r2.article_set.add(new_article2) 74 >>> new_article2.reporter 75 <Reporter: Paul Jones> 76 77 >>> r.article_set.all() 78 [<Article: John's second story>, <Article: This is a test>] 79 >>> r2.article_set.all() 80 [<Article: Paul's story>] 81 82 >>> r.article_set.count() 83 2 84 85 >>> r2.article_set.count() 86 1 87 88 Note that in the last example the article has moved from John to Paul. 89 90 Related managers support field lookups as well. 91 The API automatically follows relationships as far as you need. 92 Use double underscores to separate relationships. 93 This works as many levels deep as you want. There's no limit. For example:: 94 95 >>> r.article_set.filter(headline__startswith='This') 96 [<Article: This is a test>] 97 98 # Find all Articles for any Reporter whose first name is "John". 99 >>> Article.objects.filter(reporter__first_name__exact='John') 100 [<Article: John's second story>, <Article: This is a test>] 101 102 # exact match is implied here 103 >>> Article.objects.filter(reporter__first_name='John') 104 [<Article: John's second story>, <Article: This is a test>] 105 106 # Query twice over the related field. This translates to an AND condition in the WHERE clause. 107 >>> Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith') 108 [<Article: John's second story>, <Article: This is a test>] 109 110 For the related lookup you can supply a primary key value or pass the related 111 object explicitly:: 112 113 >>> Article.objects.filter(reporter__pk=1) 114 [<Article: John's second story>, <Article: This is a test>] 115 >>> Article.objects.filter(reporter=1) 116 [<Article: John's second story>, <Article: This is a test>] 117 >>> Article.objects.filter(reporter=r) 118 [<Article: John's second story>, <Article: This is a test>] 119 120 >>> Article.objects.filter(reporter__in=[1,2]).distinct() 121 [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>] 122 >>> Article.objects.filter(reporter__in=[r,r2]).distinct() 123 [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>] 124 125 You can also use a queryset instead of a literal list of instances:: 126 127 >>> Article.objects.filter(reporter__in=Reporter.objects.filter(first_name='John')).distinct() 128 [<Article: John's second story>, <Article: This is a test>] 129 130 Querying in the opposite direction:: 131 132 >>> Reporter.objects.filter(article__pk=1) 133 [<Reporter: John Smith>] 134 >>> Reporter.objects.filter(article=1) 135 [<Reporter: John Smith>] 136 >>> Reporter.objects.filter(article=a) 137 [<Reporter: John Smith>] 138 139 >>> Reporter.objects.filter(article__headline__startswith='This') 140 [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>] 141 >>> Reporter.objects.filter(article__headline__startswith='This').distinct() 142 [<Reporter: John Smith>] 143 144 # Counting in the opposite direction works in conjunction with distinct() 145 >>> Reporter.objects.filter(article__headline__startswith='This').count() 146 3 147 >>> Reporter.objects.filter(article__headline__startswith='This').distinct().count() 148 1 149 150 # Queries can go round in circles. 151 >>> Reporter.objects.filter(article__reporter__first_name__startswith='John') 152 [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>] 153 >>> Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct() 154 [<Reporter: John Smith>] 155 >>> Reporter.objects.filter(article__reporter__exact=r).distinct() 156 [<Reporter: John Smith>] 157 158 If you delete a reporter, his articles will be deleted (assuming that the 159 ForeignKey was defined with :attr:`django.db.models.ForeignKey.on_delete` set to 160 ``CASCADE``, which is the default):: 161 162 >>> Article.objects.all() 163 [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>] 164 >>> Reporter.objects.order_by('first_name') 165 [<Reporter: John Smith>, <Reporter: Paul Jones>] 166 >>> r2.delete() 167 >>> Article.objects.all() 168 [<Article: John's second story>, <Article: This is a test>] 169 >>> Reporter.objects.order_by('first_name') 170 [<Reporter: John Smith>] 171 172 # You can delete using a JOIN in the query. 173 >>> Reporter.objects.filter(article__headline__startswith='This').delete() 174 >>> Reporter.objects.all() 175 [] 176 >>> Article.objects.all() 177 [] -
new file docs/topics/db/examples/one_to_one.txt
diff --git a/docs/topics/db/examples/one_to_one.txt b/docs/topics/db/examples/one_to_one.txt new file mode 100644 index 0000000..32342f9
- + 1 ######################## 2 One-to-one relationships 3 ######################## 4 5 To define a one-to-one relationship, use :ref:`ref-onetoone`. 6 7 In this example, a ``Place`` optionally can be a ``Restaurant``:: 8 9 from django.db import models, transaction, IntegrityError 10 11 class Place(models.Model): 12 name = models.CharField(max_length=50) 13 address = models.CharField(max_length=80) 14 15 def __unicode__(self): 16 return u"%s the place" % self.name 17 18 class Restaurant(models.Model): 19 place = models.OneToOneField(Place, primary_key=True) 20 serves_hot_dogs = models.BooleanField() 21 serves_pizza = models.BooleanField() 22 23 def __unicode__(self): 24 return u"%s the restaurant" % self.place.name 25 26 class Waiter(models.Model): 27 restaurant = models.ForeignKey(Restaurant) 28 name = models.CharField(max_length=50) 29 30 def __unicode__(self): 31 return u"%s the waiter at %s" % (self.name, self.restaurant) 32 33 What follows are examples of operations that can be performed using the Python 34 API facilities:: 35 36 >>> # Create a couple of Places. 37 >>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton') 38 >>> p1.save() 39 >>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland') 40 >>> p2.save() 41 42 # Create a Restaurant. Pass the ID of the "parent" object as this object's ID. 43 >>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False) 44 >>> r.save() 45 46 # A Restaurant can access its place. 47 >>> r.place 48 <Place: Demon Dogs the place> 49 50 # A Place can access its restaurant, if available. 51 >>> p1.restaurant 52 <Restaurant: Demon Dogs the restaurant> 53 54 # p2 doesn't have an associated restaurant. 55 >>> p2.restaurant 56 Traceback (most recent call last): 57 ... 58 DoesNotExist: Restaurant matching query does not exist. 59 60 # Set the place using assignment notation. Because place is the primary key on 61 # Restaurant, the save will create a new restaurant 62 >>> r.place = p2 63 >>> r.save() 64 >>> p2.restaurant 65 <Restaurant: Ace Hardware the restaurant> 66 >>> r.place 67 <Place: Ace Hardware the place> 68 69 # Set the place back again, using assignment in the reverse direction. 70 >>> p1.restaurant = r 71 >>> p1.restaurant 72 <Restaurant: Demon Dogs the restaurant> 73 74 # Restaurant.objects.all() just returns the Restaurants, not the Places. 75 # Note that there are two restaurants - Ace Hardware the Restaurant was created 76 # in the call to r.place = p2. 77 >>> Restaurant.objects.all() 78 [<Restaurant: Demon Dogs the restaurant>, <Restaurant: Ace Hardware the restaurant>] 79 80 # Place.objects.all() returns all Places, regardless of whether they have 81 # Restaurants. 82 >>> Place.objects.order_by('name') 83 [<Place: Ace Hardware the place>, <Place: Demon Dogs the place>] 84 85 You can query the models using :ref:`lookups across relationships <lookups-that-span-relationships>`:: 86 87 >>> Restaurant.objects.get(place=p1) 88 <Restaurant: Demon Dogs the restaurant> 89 >>> Restaurant.objects.get(place__pk=1) 90 <Restaurant: Demon Dogs the restaurant> 91 >>> Restaurant.objects.filter(place__name__startswith="Demon") 92 [<Restaurant: Demon Dogs the restaurant>] 93 >>> Restaurant.objects.exclude(place__address__contains="Ashland") 94 [<Restaurant: Demon Dogs the restaurant>] 95 96 This of course works in reverse:: 97 98 >>> Place.objects.get(pk=1) 99 <Place: Demon Dogs the place> 100 >>> Place.objects.get(restaurant__place__exact=p1) 101 <Place: Demon Dogs the place> 102 >>> Place.objects.get(restaurant=r) 103 <Place: Demon Dogs the place> 104 >>> Place.objects.get(restaurant__place__name__startswith="Demon") 105 <Place: Demon Dogs the place> 106 107 Other related objects can also access the one-to-one relationship:: 108 109 # Add a Waiter to the Restaurant. 110 >>> w = r.waiter_set.create(name='Joe') 111 >>> w.save() 112 >>> w 113 <Waiter: Joe the waiter at Demon Dogs the restaurant> 114 115 # Query the waiters 116 >>> Waiter.objects.filter(restaurant__place=p1) 117 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] 118 >>> Waiter.objects.filter(restaurant__place__name__startswith="Demon") 119 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] -
docs/topics/db/models.txt
diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt index 65b2d59..0a16057 100644
a b The basics: 18 18 * With all of this, Django gives you an automatically-generated 19 19 database-access API; see :doc:`/topics/db/queries`. 20 20 21 .. seealso::22 23 A companion to this document is the `official repository of model24 examples`_. (In the Django source distribution, these examples are in the25 ``tests/modeltests`` directory.)26 27 .. _official repository of model examples: http://code.djangoproject.com/browser/django/trunk/tests/modeltests28 29 21 Quick example 30 22 ============= 31 23 … … whatever you want. For example:: 326 318 For details on accessing backwards-related objects, see the 327 319 :ref:`Following relationships backward example <backwards-related-objects>`. 328 320 329 For sample code, see the `Many-to-one relationship model tests`_. 330 331 .. _Many-to-one relationship model tests: http://code.djangoproject.com/browser/django/trunk/tests/modeltests/many_to_one 321 For sample code, see the :doc:`Many-to-one relationship examples 322 </topics/db/examples/many_to_one>`. 332 323 333 324 Many-to-many relationships 334 325 ~~~~~~~~~~~~~~~~~~~~~~~~~~ … … form would let users select the toppings. 376 367 377 368 .. seealso:: 378 369 379 See the `Many-to-many relationship model example`_ for a full example. 380 381 .. _Many-to-many relationship model example: http://code.djangoproject.com/browser/django/trunk/tests/modeltests/many_to_many/models.py 370 See the :doc:`Many-to-many relationship model example 371 </topics/db/examples/many_to_many>` for a full example. 382 372 383 373 :class:`~django.db.models.ManyToManyField` fields also accept a number of extra 384 374 arguments which are explained in :ref:`the model field reference … … can be made; see :ref:`the model field reference <ref-onetoone>` for details. 569 559 570 560 .. seealso:: 571 561 572 See the `One-to-one relationship model example`_ for a full example. 573 574 .. _One-to-one relationship model example: http://code.djangoproject.com/browser/django/trunk/tests/modeltests/one_to_one/models.py 562 See the :doc:`One-to-one relationship model example 563 </topics/db/examples/one_to_one>` for a full example. 575 564 576 565 :class:`~django.db.models.OneToOneField` fields also accept one optional argument 577 566 described in the :ref:`model field reference <ref-onetoone>`. -
docs/topics/db/queries.txt
diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt index 345687e..bf21b38 100644
a b you'll probably use: 444 444 Again, this only scratches the surface. A complete reference can be found in the 445 445 :ref:`field lookup reference <field-lookups>`. 446 446 447 .. _lookups-that-span-relationships: 448 447 449 Lookups that span relationships 448 450 ------------------------------- 449 451