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.utils.functional import curry
|
||||||
from django.db import backend, connection
|
from django.db import backend, connection
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
@ -51,9 +50,6 @@ class Manager(QuerySet):
|
||||||
def _prepare(self):
|
def _prepare(self):
|
||||||
if self.klass._meta.get_latest_by:
|
if self.klass._meta.get_latest_by:
|
||||||
self.get_latest = self.__get_latest
|
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):
|
def contribute_to_class(self, klass, name):
|
||||||
# TODO: Use weakref because of possible memory leak / circular reference.
|
# TODO: Use weakref because of possible memory leak / circular reference.
|
||||||
|
@ -101,29 +97,6 @@ class Manager(QuerySet):
|
||||||
kwargs['limit'] = 1
|
kwargs['limit'] = 1
|
||||||
return self.get_object(*args, **kwargs)
|
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):
|
class ManagerDescriptor(object):
|
||||||
# This class ensures managers aren't accessible via model instances.
|
# This class ensures managers aren't accessible via model instances.
|
||||||
# For example, Poll.objects works, but poll_obj.objects raises AttributeError.
|
# For example, Poll.objects works, but poll_obj.objects raises AttributeError.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.db import backend, connection
|
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
|
from django.utils.datastructures import SortedDict
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
|
@ -180,6 +180,35 @@ class QuerySet(object):
|
||||||
_, sql, params = del_query._get_sql_clause(False)
|
_, sql, params = del_query._get_sql_clause(False)
|
||||||
cursor.execute("DELETE " + sql, params)
|
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 #
|
# 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
|
In addition to every function described in "Basic lookup functions" above, a
|
||||||
model module might get any or all of the following methods:
|
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
|
Every manager has a ``dates()`` method, which returns a list of
|
||||||
``get_FOO_list()`` function, where ``FOO`` is the name of the field. This
|
``datetime.datetime`` objects representing all available dates with the given
|
||||||
returns a list of ``datetime.datetime`` objects representing all available
|
filters (if any) and of the given scope, as defined by the ``kind`` argument.
|
||||||
dates of the given scope, as defined by the ``kind`` argument. ``kind`` should
|
|
||||||
be either ``"year"``, ``"month"`` or ``"day"``. Each ``datetime.datetime``
|
``field`` should be the name of a ``DateField`` or ``DateTimeField`` of your
|
||||||
object in the result list is "truncated" to the given ``type``.
|
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.
|
* ``"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.
|
* ``"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.
|
* ``"day"`` returns a list of all distinct year/month/day values for the field.
|
||||||
|
|
||||||
Additional, optional keyword arguments, in the format described in
|
``order``, which defaults to ``'ASC'``, should be either ``"ASC"`` or ``"DESC"``.
|
||||||
"Field lookups" above, are also accepted.
|
This specifies how to order the results.
|
||||||
|
|
||||||
Here's an example, using the ``Poll`` model defined above::
|
Here's an example, using the ``Poll`` model defined above::
|
||||||
|
|
||||||
>>> from datetime import datetime
|
>>> 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))
|
... pub_date=datetime(2005, 2, 20), expire_date=datetime(2005, 3, 20))
|
||||||
>>> p1.save()
|
>>> 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))
|
... pub_date=datetime(2005, 3, 20), expire_date=datetime(2005, 4, 20))
|
||||||
>>> p2.save()
|
>>> p2.save()
|
||||||
>>> polls.get_pub_date_list('year')
|
>>> Poll.objects.dates('pub_date', 'year')
|
||||||
[datetime.datetime(2005, 1, 1)]
|
[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)]
|
[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)]
|
[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)]
|
[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)
|
>>> Article.objects.get(id__exact=8) == Article.objects.get(id__exact=7)
|
||||||
False
|
False
|
||||||
|
|
||||||
>>> Article.objects.get_pub_date_list('year')
|
>>> Article.objects.dates('pub_date', 'year')
|
||||||
[datetime.datetime(2005, 1, 1, 0, 0)]
|
[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)]
|
[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)]
|
[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)]
|
[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)]
|
[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
|
# Try some bad arguments to dates().
|
||||||
>>> Article.objects.get_pub_date_list('badarg')
|
|
||||||
|
>>> 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):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
AssertionError: 'kind' must be one of 'year', 'month' or 'day'.
|
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):
|
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 |
|
# You can combine queries with & and |
|
||||||
>>> s1 = Article.objects.filter(id__exact=1)
|
>>> s1 = Article.objects.filter(id__exact=1)
|
||||||
|
|
Loading…
Reference in New Issue