Ticket #11557: django-11557.patch

File django-11557.patch, 6.7 KB (added by Forest Bond, 14 years ago)

Improved patch with documentation.

  • django/db/models/query.py

    === modified file 'django/db/models/query.py'
     
    380380                except self.model.DoesNotExist:
    381381                    raise e
    382382
    383     def latest(self, field_name=None):
     383    def latest(self, *field_names, **kwargs):
    384384        """
    385385        Returns the latest object, according to the model's 'get_latest_by'
    386386        option or optional given field_name.
    387387        """
    388         latest_by = field_name or self.model._meta.get_latest_by
    389         assert bool(latest_by), "latest() requires either a field_name parameter or 'get_latest_by' in the model"
     388        if field_names:
     389            assert not kwargs, "latest(): keyword arguments should not be passed with positional arguments"
     390        else:
     391            try:
     392                # For backwards compatibility, handle field_name keyword
     393                # argument:
     394                field_names = (kwargs['field_name'],)
     395            except KeyError, e:
     396                field_names = ()
     397
     398        if field_names:
     399            latest_by = field_names
     400        else:
     401            latest_by = self.model._meta.get_latest_by
     402            if isinstance(latest_by, basestring):
     403                latest_by = (latest_by,)
     404
     405        assert bool(latest_by), "latest() requires one or more field_name parameters or 'get_latest_by' in the model"
    390406        assert self.query.can_filter(), \
    391407                "Cannot change a query once a slice has been taken."
     408
    392409        obj = self._clone()
    393410        obj.query.set_limits(high=1)
    394         obj.query.add_ordering('-%s' % latest_by)
     411        for s in latest_by:
     412            obj.query.add_ordering('-%s' % s)
    395413        return obj.get()
    396414
    397415    def in_bulk(self, id_list):
  • docs/ref/models/options.txt

    === modified file 'docs/ref/models/options.txt'
     
    7575
    7676.. attribute:: Options.get_latest_by
    7777
    78 The name of a :class:`DateField` or :class:`DateTimeField` in the model. This
    79 specifies the default field to use in your model :class:`Manager`'s
    80 :class:`~QuerySet.latest` method.
    81 
    82 Example::
    83 
     78The name of one or more fields (often a single :class:`DateField` or
     79:class:`DateTimeField`) in the model. This specifies the default field(s)
     80to use in your model :class:`Manager`'s :class:`~QuerySet.latest` method.
     81
     82This can either be a tuple or list of strings, or a string specifying a
     83single column.
     84
     85Examples::
     86
     87    get_latest_by = ("pub_date", "sort_order")
    8488    get_latest_by = "order_date"
    8589
    8690See the docs for :meth:`~django.db.models.QuerySet.latest` for more.
  • docs/ref/models/querysets.txt

    === modified file 'docs/ref/models/querysets.txt'
     
    11491149
    11501150.. _iterator: http://www.python.org/dev/peps/pep-0234/
    11511151
    1152 ``latest(field_name=None)``
     1152``latest(*field_names)``
    11531153~~~~~~~~~~~~~~~~~~~~~~~~~~~
    11541154
    1155 .. method:: latest(field_name=None)
     1155.. method:: latest(*field_names)
    11561156
    1157 Returns the latest object in the table, by date, using the ``field_name``
    1158 provided as the date field.
     1157Returns the last object in the table with rows ordered according to
     1158``field_names``.  field_names is typically a single date field.
    11591159
    11601160This example returns the latest ``Entry`` in the table, according to the
    11611161``pub_date`` field::
    11621162
    11631163    Entry.objects.latest('pub_date')
    11641164
    1165 If your model's ``Meta`` specifies ``get_latest_by``, you can leave off the
    1166 ``field_name`` argument to ``latest()``. Django will use the field specified in
     1165With multiple fields, arguments are interpreted as for the ``order_by`` method.
     1166
     1167If your model's ``Meta`` specifies ``get_latest_by``, no ``field_names`` need to
     1168be passed to ``latest()``.  Django will use the field(s) specified in
    11671169``get_latest_by`` by default.
    11681170
    11691171Like ``get()``, ``latest()`` raises ``DoesNotExist`` if an object doesn't
  • tests/modeltests/get_latest/models.py

    === modified file 'tests/modeltests/get_latest/models.py'
     
    2828
    2929    def __unicode__(self):
    3030        return self.name
     31
     32class ArticleLatestByMultiple(Article):
     33    class Meta:
     34        get_latest_by = ('pub_date', 'headline')
  • tests/modeltests/get_latest/tests.py

    === modified file 'tests/modeltests/get_latest/tests.py'
     
    22
    33from django.test import TestCase
    44
    5 from models import Article, Person
     5from models import Article, Person, ArticleLatestByMultiple
    66
    77
    88class LatestTests(TestCase):
     
    3838        # Pass a custom field name to latest() to change the field that's used
    3939        # to determine the latest object.
    4040        self.assertEqual(Article.objects.latest('expire_date'), a1)
     41        # Test backwards compatibility with keyword argument syntax:
     42        self.assertEqual(Article.objects.latest(field_name='expire_date'), a1)
    4143        self.assertEqual(
    4244            Article.objects.filter(pub_date__gt=datetime(2005, 7, 26)).latest('expire_date'),
    4345            a3,
     
    5153        self.assertRaises(AssertionError, Person.objects.latest)
    5254
    5355        self.assertEqual(Person.objects.latest("birthday"), p2)
     56
     57    def test_latest_by_multiple(self):
     58        a4 = ArticleLatestByMultiple.objects.create(
     59            headline="Article 4", pub_date=datetime(2005, 7, 26),
     60            expire_date=datetime(2005, 9, 1)
     61        )
     62        a3 = ArticleLatestByMultiple.objects.create(
     63            headline="Article 3", pub_date=datetime(2005, 7, 26),
     64            expire_date=datetime(2005, 7, 28)
     65        )
     66        a2 = ArticleLatestByMultiple.objects.create(
     67            headline="Article 2", pub_date=datetime(2005, 7, 27),
     68            expire_date=datetime(2005, 8, 27)
     69        )
     70        a1 = ArticleLatestByMultiple.objects.create(
     71            headline="Article 1", pub_date=datetime(2005, 7, 27),
     72            expire_date=datetime(2005, 9, 30)
     73        )
     74
     75        # Get the latest ArticleLatestByMultiple.
     76        self.assertEqual(ArticleLatestByMultiple.objects.latest(), a2)
     77        # Get the latest ArticleLatestByMultiple that matches certain filters.
     78        self.assertEqual(
     79            ArticleLatestByMultiple.objects.filter(pub_date__lt=datetime(2005, 7, 27)).latest(),
     80            a4
     81        )
     82
     83        # Pass a custom field name to latest() to change the field that's used
     84        # to determine the latest object.
     85        self.assertEqual(ArticleLatestByMultiple.objects.latest('expire_date', 'headline'), a1)
     86        self.assertEqual(ArticleLatestByMultiple.objects.latest('headline', 'expire_date'), a4)
Back to Top