Ticket #17813: t17813.2.diff
File t17813.2.diff, 17.2 KB (added by , 13 years ago) |
---|
-
django/db/models/base.py
diff --git a/django/db/models/base.py b/django/db/models/base.py index 53b62df..0996695 100644
a b class ModelBase(type): 71 71 # method resolution order). 72 72 if not hasattr(meta, 'ordering'): 73 73 new_class._meta.ordering = base_meta.ordering 74 if not hasattr(meta, 'get_earliest_by'): 75 new_class._meta.get_earliest_by = base_meta.get_earliest_by 74 76 if not hasattr(meta, 'get_latest_by'): 75 77 new_class._meta.get_latest_by = base_meta.get_latest_by 76 78 -
django/db/models/manager.py
diff --git a/django/db/models/manager.py b/django/db/models/manager.py index e1bbf6e..cc00fed 100644
a b class Manager(object): 160 160 def iterator(self, *args, **kwargs): 161 161 return self.get_query_set().iterator(*args, **kwargs) 162 162 163 def earliest(self, *args, **kwargs): 164 return self.get_query_set().earliest(*args, **kwargs) 165 163 166 def latest(self, *args, **kwargs): 164 167 return self.get_query_set().latest(*args, **kwargs) 165 168 -
django/db/models/options.py
diff --git a/django/db/models/options.py b/django/db/models/options.py index 44f8891..b88aee0 100644
a b from django.utils.datastructures import SortedDict 15 15 get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip() 16 16 17 17 DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'db_table', 'ordering', 18 'unique_together', 'permissions', 'get_ latest_by',18 'unique_together', 'permissions', 'get_earliest_by', 'get_latest_by', 19 19 'order_with_respect_to', 'app_label', 'db_tablespace', 20 20 'abstract', 'managed', 'proxy', 'auto_created') 21 21 … … class Options(object): 30 30 self.unique_together = [] 31 31 self.permissions = [] 32 32 self.object_name, self.app_label = None, app_label 33 self.get_earliest_by = None 33 34 self.get_latest_by = None 34 35 self.order_with_respect_to = None 35 36 self.db_tablespace = settings.DEFAULT_TABLESPACE -
django/db/models/query.py
diff --git a/django/db/models/query.py b/django/db/models/query.py index 44acadf..55ebc06 100644
a b class QuerySet(object): 458 458 # Re-raise the IntegrityError with its original traceback. 459 459 raise exc_info[1], None, exc_info[2] 460 460 461 def latest(self, field_name=None): 461 def _earliest_or_latest(self, field_name=None, direction="-", 462 get_by='get_latest_by'): 462 463 """ 463 Returns the latest object, according to the model's 'get_ latest_by'464 option or optional given field_name.464 Returns the latest object, according to the model's 'get_earliest_by' or 465 'get_latest_by' option or optional given field_name. 465 466 """ 466 latest_by = field_name or self.model._meta.get_latest_by 467 assert bool(latest_by), "latest() requires either a field_name parameter or 'get_latest_by' in the model" 467 order_by = field_name or getattr(self.model._meta, get_by) 468 assert bool(order_by), "_earliest_or_latest() requires either a "\ 469 "field_name parameter or '%s' in the model" % get_by 468 470 assert self.query.can_filter(), \ 469 471 "Cannot change a query once a slice has been taken." 470 472 obj = self._clone() 471 473 obj.query.set_limits(high=1) 472 474 obj.query.clear_ordering() 473 obj.query.add_ordering(' -%s' % latest_by)475 obj.query.add_ordering('%s%s' % (direction, order_by)) 474 476 return obj.get() 475 477 478 def earliest(self, field_name=None): 479 return self._earliest_or_latest(field_name=field_name, direction="", 480 get_by='get_earliest_by') 481 482 def latest(self, field_name=None): 483 return self._earliest_or_latest(field_name=field_name, direction="-") 484 476 485 def in_bulk(self, id_list): 477 486 """ 478 487 Returns a dictionary mapping each of the given IDs to the object with -
docs/ref/models/options.txt
diff --git a/docs/ref/models/options.txt b/docs/ref/models/options.txt index 6ca3d3b..fe6e1d2 100644
a b Django quotes column and table names behind the scenes. 78 78 setting, if set. If the backend doesn't support tablespaces, this option is 79 79 ignored. 80 80 81 82 ``get_earliest_by`` 83 ----------------- 84 85 .. attribute:: Options.get_earliest_by 86 87 The name of a :class:`DateField` or :class:`DateTimeField` in the model. 88 This specifies the default field to use in your model :class:`Manager`'s 89 :class:`~QuerySet.earliest` method. 90 91 Example:: 92 93 get_earliest_by = "order_date" 94 95 See the docs for :meth:`~django.db.models.query.QuerySet.earliest` for more. 96 97 81 98 ``get_latest_by`` 82 99 ----------------- 83 100 -
docs/ref/models/querysets.txt
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index e25bea0..2e67695 100644
a b This example returns the latest ``Entry`` in the table, according to the 1465 1465 Entry.objects.latest('pub_date') 1466 1466 1467 1467 If your model's :ref:`Meta <meta-options>` specifies 1468 :attr:`~django.db.models.Options.get_ latest_by`, you can leave off the1469 ``field_name`` argument to `` latest()``. Django will use the field specified1470 in :attr:`~django.db.models.Options.get_ latest_by` by default.1468 :attr:`~django.db.models.Options.get_earliest_by`, you can leave off the 1469 ``field_name`` argument to ``earliest()``. Django will use the field specified 1470 in :attr:`~django.db.models.Options.get_earliest_by` by default. 1471 1471 1472 Like :meth:`get()`, ``latest()`` raises 1473 :exc:`~django.core.exceptions.DoesNotExist` if there is no object with the given 1474 parameters. 1472 Same goes for :attr:`~django.db.models.Options.get_earliest_by` and ``latest()``. 1473 1474 Like :meth:`get()`, ``earliest()`` and ``latest()`` raise 1475 :exc:`~django.core.exceptions.DoesNotExist` if there is no object with the 1476 given parameters. 1475 1477 1476 Note ``latest()`` exists purely for convenience and readability. 1478 Note that ``earliest()`` and ``latest()`` exist purely for convenience and 1479 readability. 1477 1480 1478 1481 aggregate 1479 1482 ~~~~~~~~~ -
docs/topics/db/models.txt
diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt index 65b2d59..36019fb 100644
a b right). 991 991 992 992 So a child model does not have access to its parent's :ref:`Meta 993 993 <meta-options>` class. However, there are a few limited cases where the child 994 inherits behavior from the parent: if the child does not specify an 995 :attr:`~django.db.models.Options.ordering` attribute or a 996 :attr:`~django.db.models.Options.get_latest_by` attribute, it will inherit 997 these from its parent. 994 inherits behavior from the parent: if the child does not specify an attribute 995 :attr:`~django.db.models.Options.ordering`, 996 :attr:`~django.db.models.Options.get_earliest_by`, or 997 :attr:`~django.db.models.Options.get_latest_by`, 998 , it will inherit these from its parent. 998 999 999 1000 If the parent has an ordering and you don't want the child to have any natural 1000 1001 ordering, you can explicitly disable it:: -
new file tests/modeltests/get_earliest_or_latest/models.py
diff --git a/tests/modeltests/get_earliest_or_latest/__init__.py b/tests/modeltests/get_earliest_or_latest/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modeltests/get_earliest_or_latest/models.py b/tests/modeltests/get_earliest_or_latest/models.py new file mode 100644 index 0000000..72e5781
- + 1 """ 2 8. get_latest_by 3 4 Models can have a ``get_latest_by`` attribute, which should be set to the name 5 of a ``DateField`` or ``DateTimeField``. If ``get_latest_by`` exists, the 6 model's manager will get a ``latest()`` method, which will return the latest 7 object in the database according to that field. "Latest" means "having the date 8 farthest into the future." 9 """ 10 11 from django.db import models 12 13 14 class Article(models.Model): 15 headline = models.CharField(max_length=100) 16 pub_date = models.DateField() 17 expire_date = models.DateField() 18 class Meta: 19 get_earliest_by = 'pub_date' 20 get_latest_by = 'pub_date' 21 22 def __unicode__(self): 23 return self.headline 24 25 26 class Person(models.Model): 27 name = models.CharField(max_length=30) 28 birthday = models.DateField() 29 30 # Note that this model doesn't have "get_latest_by" set. 31 32 def __unicode__(self): 33 return self.name -
new file tests/modeltests/get_earliest_or_latest/tests.py
diff --git a/tests/modeltests/get_earliest_or_latest/tests.py b/tests/modeltests/get_earliest_or_latest/tests.py new file mode 100644 index 0000000..a78af2a
- + 1 from __future__ import absolute_import 2 3 from datetime import datetime 4 5 from django.test import TestCase 6 7 from .models import Article, Person 8 9 10 class EarliestOrLatestTests(TestCase): 11 """Tests for the earliest() and latest() objects methods""" 12 13 def test_earliest(self): 14 # Because no Articles exist yet, earliest() raises ArticleDoesNotExist. 15 self.assertRaises(Article.DoesNotExist, Article.objects.earliest) 16 17 a1 = Article.objects.create( 18 headline="Article 1", pub_date=datetime(2005, 7, 26), 19 expire_date=datetime(2005, 9, 1) 20 ) 21 a2 = Article.objects.create( 22 headline="Article 2", pub_date=datetime(2005, 7, 27), 23 expire_date=datetime(2005, 7, 28) 24 ) 25 a3 = Article.objects.create( 26 headline="Article 3", pub_date=datetime(2005, 7, 28), 27 expire_date=datetime(2005, 8, 27) 28 ) 29 a4 = Article.objects.create( 30 headline="Article 4", pub_date=datetime(2005, 7, 28), 31 expire_date=datetime(2005, 7, 30) 32 ) 33 34 # Get the earliest Article. 35 self.assertEqual(Article.objects.earliest(), a1) 36 # Get the earliest Article that matches certain filters. 37 self.assertEqual( 38 Article.objects.filter(pub_date__gt=datetime(2005, 7, 26)).earliest(), 39 a2 40 ) 41 42 # Pass a custom field name to earliest() to change the field that's used 43 # to determine the earliest object. 44 self.assertEqual(Article.objects.earliest('expire_date'), a2) 45 self.assertEqual(Article.objects.filter( 46 pub_date__gt=datetime(2005, 7, 26)).earliest('expire_date'), a2) 47 48 # Ensure that earliest() overrides any other ordering specified on the 49 # query. Refs #11283. 50 self.assertEqual(Article.objects.order_by('id').earliest(), a1) 51 52 # Ensure that error is raised if the user forgot to add a get_earliest_by 53 # in the Model.Meta 54 Article.objects.model._meta.get_earliest_by = None 55 self.assertRaisesMessage( 56 AssertionError, 57 "_earliest_or_latest() requires either a field_name parameter or "\ 58 "'get_earliest_by' in the model", 59 lambda: Article.objects.earliest(), 60 ) 61 62 63 def test_latest(self): 64 # Because no Articles exist yet, latest() raises ArticleDoesNotExist. 65 self.assertRaises(Article.DoesNotExist, Article.objects.latest) 66 67 a1 = Article.objects.create( 68 headline="Article 1", pub_date=datetime(2005, 7, 26), 69 expire_date=datetime(2005, 9, 1) 70 ) 71 a2 = Article.objects.create( 72 headline="Article 2", pub_date=datetime(2005, 7, 27), 73 expire_date=datetime(2005, 7, 28) 74 ) 75 a3 = Article.objects.create( 76 headline="Article 3", pub_date=datetime(2005, 7, 27), 77 expire_date=datetime(2005, 8, 27) 78 ) 79 a4 = Article.objects.create( 80 headline="Article 4", pub_date=datetime(2005, 7, 28), 81 expire_date=datetime(2005, 7, 30) 82 ) 83 84 # Get the latest Article. 85 self.assertEqual(Article.objects.latest(), a4) 86 # Get the latest Article that matches certain filters. 87 self.assertEqual( 88 Article.objects.filter(pub_date__lt=datetime(2005, 7, 27)).latest(), 89 a1 90 ) 91 92 # Pass a custom field name to latest() to change the field that's used 93 # to determine the latest object. 94 self.assertEqual(Article.objects.latest('expire_date'), a1) 95 self.assertEqual( 96 Article.objects.filter(pub_date__gt=datetime(2005, 7, 26)).latest('expire_date'), 97 a3, 98 ) 99 100 # Ensure that latest() overrides any other ordering specified on the query. Refs #11283. 101 self.assertEqual(Article.objects.order_by('id').latest(), a4) 102 103 # Ensure that error is raised if the user forgot to add a get_latest_by 104 # in the Model.Meta 105 Article.objects.model._meta.get_latest_by = None 106 self.assertRaisesMessage( 107 AssertionError, 108 "_earliest_or_latest() requires either a field_name parameter or "\ 109 "'get_latest_by' in the model", 110 lambda: Article.objects.latest(), 111 ) 112 113 114 def test_latest_manual(self): 115 # You can still use latest() with a model that doesn't have 116 # "get_latest_by" set -- just pass in the field name manually. 117 p1 = Person.objects.create(name="Ralph", birthday=datetime(1950, 1, 1)) 118 p2 = Person.objects.create(name="Stephanie", birthday=datetime(1960, 2, 3)) 119 self.assertRaises(AssertionError, Person.objects.latest) 120 121 self.assertEqual(Person.objects.latest("birthday"), p2) -
deleted file tests/modeltests/get_latest/models.py
diff --git a/tests/modeltests/get_latest/__init__.py b/tests/modeltests/get_latest/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/modeltests/get_latest/models.py b/tests/modeltests/get_latest/models.py deleted file mode 100644 index d8a690f..0000000
+ - 1 """2 8. get_latest_by3 4 Models can have a ``get_latest_by`` attribute, which should be set to the name5 of a ``DateField`` or ``DateTimeField``. If ``get_latest_by`` exists, the6 model's manager will get a ``latest()`` method, which will return the latest7 object in the database according to that field. "Latest" means "having the date8 farthest into the future."9 """10 11 from django.db import models12 13 14 class Article(models.Model):15 headline = models.CharField(max_length=100)16 pub_date = models.DateField()17 expire_date = models.DateField()18 class Meta:19 get_latest_by = 'pub_date'20 21 def __unicode__(self):22 return self.headline23 24 class Person(models.Model):25 name = models.CharField(max_length=30)26 birthday = models.DateField()27 28 # Note that this model doesn't have "get_latest_by" set.29 30 def __unicode__(self):31 return self.name -
deleted file tests/modeltests/get_latest/tests.py
diff --git a/tests/modeltests/get_latest/tests.py b/tests/modeltests/get_latest/tests.py deleted file mode 100644 index 948af60..0000000
+ - 1 from __future__ import absolute_import2 3 from datetime import datetime4 5 from django.test import TestCase6 7 from .models import Article, Person8 9 10 class LatestTests(TestCase):11 def test_latest(self):12 # Because no Articles exist yet, latest() raises ArticleDoesNotExist.13 self.assertRaises(Article.DoesNotExist, Article.objects.latest)14 15 a1 = Article.objects.create(16 headline="Article 1", pub_date=datetime(2005, 7, 26),17 expire_date=datetime(2005, 9, 1)18 )19 a2 = Article.objects.create(20 headline="Article 2", pub_date=datetime(2005, 7, 27),21 expire_date=datetime(2005, 7, 28)22 )23 a3 = Article.objects.create(24 headline="Article 3", pub_date=datetime(2005, 7, 27),25 expire_date=datetime(2005, 8, 27)26 )27 a4 = Article.objects.create(28 headline="Article 4", pub_date=datetime(2005, 7, 28),29 expire_date=datetime(2005, 7, 30)30 )31 32 # Get the latest Article.33 self.assertEqual(Article.objects.latest(), a4)34 # Get the latest Article that matches certain filters.35 self.assertEqual(36 Article.objects.filter(pub_date__lt=datetime(2005, 7, 27)).latest(),37 a138 )39 40 # Pass a custom field name to latest() to change the field that's used41 # to determine the latest object.42 self.assertEqual(Article.objects.latest('expire_date'), a1)43 self.assertEqual(44 Article.objects.filter(pub_date__gt=datetime(2005, 7, 26)).latest('expire_date'),45 a3,46 )47 48 # Ensure that latest() overrides any other ordering specified on the query. Refs #11283.49 self.assertEqual(Article.objects.order_by('id').latest(), a4)50 51 def test_latest_manual(self):52 # You can still use latest() with a model that doesn't have53 # "get_latest_by" set -- just pass in the field name manually.54 p1 = Person.objects.create(name="Ralph", birthday=datetime(1950, 1, 1))55 p2 = Person.objects.create(name="Stephanie", birthday=datetime(1960, 2, 3))56 self.assertRaises(AssertionError, Person.objects.latest)57 58 self.assertEqual(Person.objects.latest("birthday"), p2)