Ticket #17813: t17813.3.2.diff
File t17813.3.2.diff, 12.4 KB (added by , 13 years ago) |
---|
-
django/db/models/manager.py
diff --git a/django/db/models/manager.py b/django/db/models/manager.py index e1bbf6e..abff034 100644
a b def ensure_default_manager(sender, **kwargs): 42 42 43 43 signals.class_prepared.connect(ensure_default_manager) 44 44 45 45 46 class Manager(object): 46 47 # Tracks each time a Manager instance is created. Used to retain order. 47 48 creation_counter = 0 … … class Manager(object): 160 161 def iterator(self, *args, **kwargs): 161 162 return self.get_query_set().iterator(*args, **kwargs) 162 163 164 def earliest(self, *args, **kwargs): 165 return self.get_query_set().earliest(*args, **kwargs) 166 163 167 def latest(self, *args, **kwargs): 164 168 return self.get_query_set().latest(*args, **kwargs) 165 169 … … class Manager(object): 208 212 def raw(self, raw_query, params=None, *args, **kwargs): 209 213 return RawQuerySet(raw_query=raw_query, model=self.model, params=params, using=self._db, *args, **kwargs) 210 214 215 211 216 class ManagerDescriptor(object): 212 217 # This class ensures managers aren't accessible via model instances. 213 218 # For example, Poll.objects works, but poll_obj.objects raises AttributeError. … … class ManagerDescriptor(object): 219 224 raise AttributeError("Manager isn't accessible via %s instances" % type.__name__) 220 225 return self.manager 221 226 227 222 228 class EmptyManager(Manager): 223 229 def get_query_set(self): 224 230 return self.get_empty_query_set() -
django/db/models/query.py
diff --git a/django/db/models/query.py b/django/db/models/query.py index 44acadf..d1319d0 100644
a b REPR_OUTPUT_SIZE = 20 25 25 # Pull into this namespace for backwards compatibility. 26 26 EmptyResultSet = sql.EmptyResultSet 27 27 28 28 29 class QuerySet(object): 29 30 """ 30 31 Represents a lazy database lookup for a set of objects. … … class QuerySet(object): 458 459 # Re-raise the IntegrityError with its original traceback. 459 460 raise exc_info[1], None, exc_info[2] 460 461 461 def latest(self, field_name=None):462 def _earliest_or_latest(self, field_name=None, direction="-"): 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 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_latest_by') 468 assert bool(order_by), "_earliest_or_latest() requires either a "\ 469 "field_name parameter or 'get_latest_by' in the model" 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 481 def latest(self, field_name=None): 482 return self._earliest_or_latest(field_name=field_name, direction="-") 483 476 484 def in_bulk(self, id_list): 477 485 """ 478 486 Returns a dictionary mapping each of the given IDs to the object with … … class EmptyQuerySet(QuerySet): 1237 1245 # situations). 1238 1246 value_annotation = False 1239 1247 1248 1240 1249 def get_klass_info(klass, max_depth=0, cur_depth=0, requested=None, 1241 1250 only_load=None, local_only=False): 1242 1251 """ -
docs/ref/models/options.txt
diff --git a/docs/ref/models/options.txt b/docs/ref/models/options.txt index 6ca3d3b..3e77b8b 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 81 82 ``get_latest_by`` 82 83 ----------------- 83 84 -
docs/ref/models/querysets.txt
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index e25bea0..34e3fac 100644
a b This example returns the latest ``Entry`` in the table, according to the 1466 1466 1467 1467 If your model's :ref:`Meta <meta-options>` specifies 1468 1468 :attr:`~django.db.models.Options.get_latest_by`, you can leave off the 1469 ``field_name`` argument to `` latest()``. Django will use the field specified1470 in :attr:`~django.db.models.Options.get_latest_by` by default.1469 ``field_name`` argument to ``earliest()`` or ``latest()``. Django will use the 1470 field specified in :attr:`~django.db.models.Options.get_latest_by` by default. 1471 1471 1472 Like :meth:`get()`, `` latest()`` raises1473 :exc:`~django.core.exceptions.DoesNotExist` if there is no object with the given1474 parameters.1472 Like :meth:`get()`, ``earliest()`` and ``latest()`` raise 1473 :exc:`~django.core.exceptions.DoesNotExist` if there is no object with the 1474 given parameters. 1475 1475 1476 Note ``latest()`` exists purely for convenience and readability. 1476 Note that ``earliest()`` and ``latest()`` exist purely for convenience and 1477 readability. 1477 1478 1478 1479 aggregate 1479 1480 ~~~~~~~~~ -
docs/topics/db/models.txt
diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt index 9b29e1e..85dbfea 100644
a b right). 973 973 974 974 So a child model does not have access to its parent's :ref:`Meta 975 975 <meta-options>` class. However, there are a few limited cases where the child 976 inherits behavior from the parent: if the child does not specify an 977 :attr:`~django.db.models.Options.ordering` attribute or a978 :attr:`~django.db.models.Options.get_latest_by` attribute, it will inherit979 these from its parent.976 inherits behavior from the parent: if the child does not specify an attribute 977 :attr:`~django.db.models.Options.ordering` or 978 :attr:`~django.db.models.Options.get_latest_by`, 979 , it will inherit these from its parent. 980 980 981 981 If the parent has an ordering and you don't want the child to have any natural 982 982 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..2453eaa
- + 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_latest_by = 'pub_date' 20 21 def __unicode__(self): 22 return self.headline 23 24 25 class Person(models.Model): 26 name = models.CharField(max_length=30) 27 birthday = models.DateField() 28 29 # Note that this model doesn't have "get_latest_by" set. 30 31 def __unicode__(self): 32 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..7dca7ed
- + 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_latest_by 53 # in the Model.Meta 54 Article.objects.model._meta.get_latest_by = None 55 self.assertRaisesMessage( 56 AssertionError, 57 "_earliest_or_latest() requires either a field_name parameter or "\ 58 "'get_latest_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)