magic-removal: Changed get_DATEFIELD_list() manager method to dates(), which takes the name of the date field. Updated docs and unit tests.

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2177 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2006-01-30 04:36:41 +00:00
parent cf276407ea
commit 97e7ff7c27
4 changed files with 91 additions and 75 deletions

View File

@ -1,4 +1,3 @@
from django.db.models.fields import DateField
from django.utils.functional import curry
from django.db import backend, connection
from django.db.models.query import QuerySet
@ -51,9 +50,6 @@ class Manager(QuerySet):
def _prepare(self):
if self.klass._meta.get_latest_by:
self.get_latest = self.__get_latest
for f in self.klass._meta.fields:
if isinstance(f, DateField):
setattr(self, 'get_%s_list' % f.name, curry(self.__get_date_list, f))
def contribute_to_class(self, klass, name):
# TODO: Use weakref because of possible memory leak / circular reference.
@ -101,29 +97,6 @@ class Manager(QuerySet):
kwargs['limit'] = 1
return self.get_object(*args, **kwargs)
def __get_date_list(self, field, kind, *args, **kwargs):
from django.db.backends.util import typecast_timestamp
assert kind in ("month", "year", "day"), "'kind' must be one of 'year', 'month' or 'day'."
order = 'ASC'
if kwargs.has_key('order'):
order = kwargs['order']
del kwargs['order']
assert order in ('ASC', 'DESC'), "'order' must be either 'ASC' or 'DESC'"
kwargs['order_by'] = () # Clear this because it'll mess things up otherwise.
if field.null:
kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % \
(backend.quote_name(self.klass._meta.db_table), backend.quote_name(field.column)))
select, sql, params = self._get_sql_clause(True, *args, **kwargs)
sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \
(backend.get_date_trunc_sql(kind, '%s.%s' % (backend.quote_name(self.klass._meta.db_table),
backend.quote_name(field.column))), sql, order)
cursor = connection.cursor()
cursor.execute(sql, params)
# We have to manually run typecast_timestamp(str()) on the results, because
# MySQL doesn't automatically cast the result of date functions as datetime
# objects -- MySQL returns the values as strings, instead.
return [typecast_timestamp(str(row[0])) for row in cursor.fetchall()]
class ManagerDescriptor(object):
# This class ensures managers aren't accessible via model instances.
# For example, Poll.objects works, but poll_obj.objects raises AttributeError.

View File

@ -1,5 +1,5 @@
from django.db import backend, connection
from django.db.models.fields import FieldDoesNotExist
from django.db.models.fields import DateField, FieldDoesNotExist
from django.utils.datastructures import SortedDict
import copy
@ -180,6 +180,35 @@ class QuerySet(object):
_, sql, params = del_query._get_sql_clause(False)
cursor.execute("DELETE " + sql, params)
def dates(self, field_name, kind, order='ASC'):
"""
Returns a list of datetime objects representing all available dates
for the given field_name, scoped to 'kind'.
"""
from django.db.backends.util import typecast_timestamp
assert kind in ("month", "year", "day"), "'kind' must be one of 'year', 'month' or 'day'."
assert order in ('ASC', 'DESC'), "'order' must be either 'ASC' or 'DESC'."
# Let the FieldDoesNotExist exception propogate.
field = self.klass._meta.get_field(field_name, many_to_many=False)
assert isinstance(field, DateField), "%r isn't a DateField." % field_name
date_query = self._clone()
date_query._order_by = () # Clear this because it'll mess things up otherwise.
if field.null:
date_query._where.append('%s.%s IS NOT NULL' % \
(backend.quote_name(self.klass._meta.db_table), backend.quote_name(field.column)))
select, sql, params = date_query._get_sql_clause(True)
sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \
(backend.get_date_trunc_sql(kind, '%s.%s' % (backend.quote_name(self.klass._meta.db_table),
backend.quote_name(field.column))), sql, order)
cursor = connection.cursor()
cursor.execute(sql, params)
# We have to manually run typecast_timestamp(str()) on the results, because
# MySQL doesn't automatically cast the result of date functions as datetime
# objects -- MySQL returns the values as strings, instead.
return [typecast_timestamp(str(row[0])) for row in cursor.fetchall()]
#############################################
# PUBLIC METHODS THAT RETURN A NEW QUERYSET #
#############################################

View File

@ -681,41 +681,43 @@ Extra module functions
In addition to every function described in "Basic lookup functions" above, a
model module might get any or all of the following methods:
get_FOO_list(kind, \**kwargs)
-----------------------------
dates(field, kind, order='ASC')
-------------------------------
For every ``DateField`` and ``DateTimeField``, the model module will have a
``get_FOO_list()`` function, where ``FOO`` is the name of the field. This
returns a list of ``datetime.datetime`` objects representing all available
dates of the given scope, as defined by the ``kind`` argument. ``kind`` should
be either ``"year"``, ``"month"`` or ``"day"``. Each ``datetime.datetime``
object in the result list is "truncated" to the given ``type``.
Every manager has a ``dates()`` method, which returns a list of
``datetime.datetime`` objects representing all available dates with the given
filters (if any) and of the given scope, as defined by the ``kind`` argument.
``field`` should be the name of a ``DateField`` or ``DateTimeField`` of your
model.
``kind`` should be either ``"year"``, ``"month"`` or ``"day"``. Each
``datetime.datetime`` object in the result list is "truncated" to the given
``type``.
* ``"year"`` returns a list of all distinct year values for the field.
* ``"month"`` returns a list of all distinct year/month values for the field.
* ``"day"`` returns a list of all distinct year/month/day values for the field.
Additional, optional keyword arguments, in the format described in
"Field lookups" above, are also accepted.
``order``, which defaults to ``'ASC'``, should be either ``"ASC"`` or ``"DESC"``.
This specifies how to order the results.
Here's an example, using the ``Poll`` model defined above::
>>> from datetime import datetime
>>> p1 = polls.Poll(slug='whatsup', question="What's up?",
>>> p1 = Poll(slug='whatsup', question="What's up?",
... pub_date=datetime(2005, 2, 20), expire_date=datetime(2005, 3, 20))
>>> p1.save()
>>> p2 = polls.Poll(slug='name', question="What's your name?",
>>> p2 = Poll(slug='name', question="What's your name?",
... pub_date=datetime(2005, 3, 20), expire_date=datetime(2005, 4, 20))
>>> p2.save()
>>> polls.get_pub_date_list('year')
>>> Poll.objects.dates('pub_date', 'year')
[datetime.datetime(2005, 1, 1)]
>>> polls.get_pub_date_list('month')
>>> Poll.objects.dates('pub_date', 'month')
[datetime.datetime(2005, 2, 1), datetime.datetime(2005, 3, 1)]
>>> polls.get_pub_date_list('day')
>>> Poll.objects.dates('pub_date', 'day')
[datetime.datetime(2005, 2, 20), datetime.datetime(2005, 3, 20)]
>>> polls.get_pub_date_list('day', question__contains='name')
>>> Poll.objects.dates('pub_date', 'day', order='DESC')
[datetime.datetime(2005, 3, 20), datetime.datetime(2005, 2, 20)]
>>> Poll.objects.filter(question__contains='name').dates('pub_date', 'day')
[datetime.datetime(2005, 3, 20)]
``get_FOO_list()`` also accepts an optional keyword argument ``order``, which
should be either ``"ASC"`` or ``"DESC"``. This specifies how to order the
results. Default is ``"ASC"``.

View File

@ -174,26 +174,38 @@ True
>>> Article.objects.get(id__exact=8) == Article.objects.get(id__exact=7)
False
>>> Article.objects.get_pub_date_list('year')
>>> Article.objects.dates('pub_date', 'year')
[datetime.datetime(2005, 1, 1, 0, 0)]
>>> Article.objects.get_pub_date_list('month')
>>> Article.objects.dates('pub_date', 'month')
[datetime.datetime(2005, 7, 1, 0, 0)]
>>> Article.objects.get_pub_date_list('day')
>>> Article.objects.dates('pub_date', 'day')
[datetime.datetime(2005, 7, 28, 0, 0), datetime.datetime(2005, 7, 29, 0, 0), datetime.datetime(2005, 7, 30, 0, 0), datetime.datetime(2005, 7, 31, 0, 0)]
>>> Article.objects.get_pub_date_list('day', order='ASC')
>>> Article.objects.dates('pub_date', 'day', order='ASC')
[datetime.datetime(2005, 7, 28, 0, 0), datetime.datetime(2005, 7, 29, 0, 0), datetime.datetime(2005, 7, 30, 0, 0), datetime.datetime(2005, 7, 31, 0, 0)]
>>> Article.objects.get_pub_date_list('day', order='DESC')
>>> Article.objects.dates('pub_date', 'day', order='DESC')
[datetime.datetime(2005, 7, 31, 0, 0), datetime.datetime(2005, 7, 30, 0, 0), datetime.datetime(2005, 7, 29, 0, 0), datetime.datetime(2005, 7, 28, 0, 0)]
# Try some bad arguments to __get_date_list
>>> Article.objects.get_pub_date_list('badarg')
# Try some bad arguments to dates().
>>> Article.objects.dates()
Traceback (most recent call last):
...
TypeError: dates() takes at least 3 arguments (1 given)
>>> Article.objects.dates('invalid_field', 'year')
Traceback (most recent call last):
...
FieldDoesNotExist: name=invalid_field
>>> Article.objects.dates('pub_date', 'bad_kind')
Traceback (most recent call last):
...
AssertionError: 'kind' must be one of 'year', 'month' or 'day'.
>>> Article.objects.get_pub_date_list(order='ASC')
>>> Article.objects.dates('pub_date', 'year', order='bad order')
Traceback (most recent call last):
...
TypeError: __get_date_list() takes at least 3 non-keyword arguments (2 given)
AssertionError: 'order' must be either 'ASC' or 'DESC'.
# You can combine queries with & and |
>>> s1 = Article.objects.filter(id__exact=1)