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:
parent
cf276407ea
commit
97e7ff7c27
|
@ -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.
|
||||
|
|
|
@ -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 #
|
||||
#############################################
|
||||
|
|
|
@ -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"``.
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue