models.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. # coding: utf-8
  2. from django.db import models
  3. from django.conf import settings
  4. try:
  5. sorted
  6. except NameError:
  7. from django.utils.itercompat import sorted # For Python 2.3
  8. class Author(models.Model):
  9. name = models.CharField(max_length=100)
  10. age = models.IntegerField()
  11. friends = models.ManyToManyField('self', blank=True)
  12. def __unicode__(self):
  13. return self.name
  14. class Publisher(models.Model):
  15. name = models.CharField(max_length=300)
  16. num_awards = models.IntegerField()
  17. def __unicode__(self):
  18. return self.name
  19. class Book(models.Model):
  20. isbn = models.CharField(max_length=9)
  21. name = models.CharField(max_length=300)
  22. pages = models.IntegerField()
  23. rating = models.FloatField()
  24. price = models.DecimalField(decimal_places=2, max_digits=6)
  25. authors = models.ManyToManyField(Author)
  26. publisher = models.ForeignKey(Publisher)
  27. pubdate = models.DateField()
  28. class Meta:
  29. ordering = ('name',)
  30. def __unicode__(self):
  31. return self.name
  32. class Store(models.Model):
  33. name = models.CharField(max_length=300)
  34. books = models.ManyToManyField(Book)
  35. original_opening = models.DateTimeField()
  36. friday_night_closing = models.TimeField()
  37. def __unicode__(self):
  38. return self.name
  39. #Extra does not play well with values. Modify the tests if/when this is fixed.
  40. __test__ = {'API_TESTS': """
  41. >>> from django.core import management
  42. >>> from django.db.models import get_app
  43. # Reset the database representation of this app.
  44. # This will return the database to a clean initial state.
  45. >>> management.call_command('flush', verbosity=0, interactive=False)
  46. >>> from django.db.models import Avg, Sum, Count, Max, Min, StdDev, Variance
  47. # Ordering requests are ignored
  48. >>> Author.objects.all().order_by('name').aggregate(Avg('age'))
  49. {'age__avg': 37.4...}
  50. # Implicit ordering is also ignored
  51. >>> Book.objects.all().aggregate(Sum('pages'))
  52. {'pages__sum': 3703}
  53. # Baseline results
  54. >>> Book.objects.all().aggregate(Sum('pages'), Avg('pages'))
  55. {'pages__sum': 3703, 'pages__avg': 617.1...}
  56. # Empty values query doesn't affect grouping or results
  57. >>> Book.objects.all().values().aggregate(Sum('pages'), Avg('pages'))
  58. {'pages__sum': 3703, 'pages__avg': 617.1...}
  59. # Aggregate overrides extra selected column
  60. >>> Book.objects.all().extra(select={'price_per_page' : 'price / pages'}).aggregate(Sum('pages'))
  61. {'pages__sum': 3703}
  62. # Annotations get combined with extra select clauses
  63. >>> sorted(Book.objects.all().annotate(mean_auth_age=Avg('authors__age')).extra(select={'manufacture_cost' : 'price * .5'}).get(pk=2).__dict__.items())
  64. [('id', 2), ('isbn', u'067232959'), ('manufacture_cost', ...11.545...), ('mean_auth_age', 45.0), ('name', u'Sams Teach Yourself Django in 24 Hours'), ('pages', 528), ('price', Decimal("23.09")), ('pubdate', datetime.date(2008, 3, 3)), ('publisher_id', 2), ('rating', 3.0)]
  65. # Order of the annotate/extra in the query doesn't matter
  66. >>> sorted(Book.objects.all().extra(select={'manufacture_cost' : 'price * .5'}).annotate(mean_auth_age=Avg('authors__age')).get(pk=2).__dict__.items())
  67. [('id', 2), ('isbn', u'067232959'), ('manufacture_cost', ...11.545...), ('mean_auth_age', 45.0), ('name', u'Sams Teach Yourself Django in 24 Hours'), ('pages', 528), ('price', Decimal("23.09")), ('pubdate', datetime.date(2008, 3, 3)), ('publisher_id', 2), ('rating', 3.0)]
  68. # Values queries can be combined with annotate and extra
  69. >>> sorted(Book.objects.all().annotate(mean_auth_age=Avg('authors__age')).extra(select={'manufacture_cost' : 'price * .5'}).values().get(pk=2).items())
  70. [('id', 2), ('isbn', u'067232959'), ('manufacture_cost', ...11.545...), ('mean_auth_age', 45.0), ('name', u'Sams Teach Yourself Django in 24 Hours'), ('pages', 528), ('price', Decimal("23.09")), ('pubdate', datetime.date(2008, 3, 3)), ('publisher_id', 2), ('rating', 3.0)]
  71. # The order of the values, annotate and extra clauses doesn't matter
  72. >>> sorted(Book.objects.all().values().annotate(mean_auth_age=Avg('authors__age')).extra(select={'manufacture_cost' : 'price * .5'}).get(pk=2).items())
  73. [('id', 2), ('isbn', u'067232959'), ('manufacture_cost', ...11.545...), ('mean_auth_age', 45.0), ('name', u'Sams Teach Yourself Django in 24 Hours'), ('pages', 528), ('price', Decimal("23.09")), ('pubdate', datetime.date(2008, 3, 3)), ('publisher_id', 2), ('rating', 3.0)]
  74. # A values query that selects specific columns reduces the output
  75. >>> sorted(Book.objects.all().annotate(mean_auth_age=Avg('authors__age')).extra(select={'price_per_page' : 'price / pages'}).values('name').get(pk=1).items())
  76. [('mean_auth_age', 34.5), ('name', u'The Definitive Guide to Django: Web Development Done Right')]
  77. # The annotations are added to values output if values() precedes annotate()
  78. >>> sorted(Book.objects.all().values('name').annotate(mean_auth_age=Avg('authors__age')).extra(select={'price_per_page' : 'price / pages'}).get(pk=1).items())
  79. [('mean_auth_age', 34.5), ('name', u'The Definitive Guide to Django: Web Development Done Right')]
  80. # Check that all of the objects are getting counted (allow_nulls) and that values respects the amount of objects
  81. >>> len(Author.objects.all().annotate(Avg('friends__age')).values())
  82. 9
  83. # Check that consecutive calls to annotate accumulate in the query
  84. >>> Book.objects.values('price').annotate(oldest=Max('authors__age')).order_by('oldest', 'price').annotate(Max('publisher__num_awards'))
  85. [{'price': Decimal("30..."), 'oldest': 35, 'publisher__num_awards__max': 3}, {'price': Decimal("29.69"), 'oldest': 37, 'publisher__num_awards__max': 7}, {'price': Decimal("23.09"), 'oldest': 45, 'publisher__num_awards__max': 1}, {'price': Decimal("75..."), 'oldest': 57, 'publisher__num_awards__max': 9}, {'price': Decimal("82.8..."), 'oldest': 57, 'publisher__num_awards__max': 7}]
  86. # Aggregates can be composed over annotations.
  87. # The return type is derived from the composed aggregate
  88. >>> Book.objects.all().annotate(num_authors=Count('authors__id')).aggregate(Max('pages'), Max('price'), Sum('num_authors'), Avg('num_authors'))
  89. {'num_authors__sum': 10, 'num_authors__avg': 1.66..., 'pages__max': 1132, 'price__max': Decimal("82.80")}
  90. # Bad field requests in aggregates are caught and reported
  91. >>> Book.objects.all().aggregate(num_authors=Count('foo'))
  92. Traceback (most recent call last):
  93. ...
  94. FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, id, isbn, name, pages, price, pubdate, publisher, rating, store
  95. >>> Book.objects.all().annotate(num_authors=Count('foo'))
  96. Traceback (most recent call last):
  97. ...
  98. FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, id, isbn, name, pages, price, pubdate, publisher, rating, store
  99. >>> Book.objects.all().annotate(num_authors=Count('authors__id')).aggregate(Max('foo'))
  100. Traceback (most recent call last):
  101. ...
  102. FieldError: Cannot resolve keyword 'foo' into field. Choices are: authors, id, isbn, name, pages, price, pubdate, publisher, rating, store, num_authors
  103. # Old-style count aggregations can be mixed with new-style
  104. >>> Book.objects.annotate(num_authors=Count('authors')).count()
  105. 6
  106. # Non-ordinal, non-computed Aggregates over annotations correctly inherit
  107. # the annotation's internal type if the annotation is ordinal or computed
  108. >>> Book.objects.annotate(num_authors=Count('authors')).aggregate(Max('num_authors'))
  109. {'num_authors__max': 3}
  110. >>> Publisher.objects.annotate(avg_price=Avg('book__price')).aggregate(Max('avg_price'))
  111. {'avg_price__max': 75.0...}
  112. # Aliases are quoted to protected aliases that might be reserved names
  113. >>> Book.objects.aggregate(number=Max('pages'), select=Max('pages'))
  114. {'number': 1132, 'select': 1132}
  115. """
  116. }
  117. if settings.DATABASE_ENGINE != 'sqlite3':
  118. __test__['API_TESTS'] += """
  119. # Stddev and Variance are not guaranteed to be available for SQLite.
  120. >>> Book.objects.aggregate(StdDev('pages'))
  121. {'pages__stddev': 311.46...}
  122. >>> Book.objects.aggregate(StdDev('rating'))
  123. {'rating__stddev': 0.60...}
  124. >>> Book.objects.aggregate(StdDev('price'))
  125. {'price__stddev': 24.16...}
  126. >>> Book.objects.aggregate(StdDev('pages', sample=True))
  127. {'pages__stddev': 341.19...}
  128. >>> Book.objects.aggregate(StdDev('rating', sample=True))
  129. {'rating__stddev': 0.66...}
  130. >>> Book.objects.aggregate(StdDev('price', sample=True))
  131. {'price__stddev': 26.46...}
  132. >>> Book.objects.aggregate(Variance('pages'))
  133. {'pages__variance': 97010.80...}
  134. >>> Book.objects.aggregate(Variance('rating'))
  135. {'rating__variance': 0.36...}
  136. >>> Book.objects.aggregate(Variance('price'))
  137. {'price__variance': 583.77...}
  138. >>> Book.objects.aggregate(Variance('pages', sample=True))
  139. {'pages__variance': 116412.96...}
  140. >>> Book.objects.aggregate(Variance('rating', sample=True))
  141. {'rating__variance': 0.44...}
  142. >>> Book.objects.aggregate(Variance('price', sample=True))
  143. {'price__variance': 700.53...}
  144. """