Fixed #7672 -- Added a 'week_day' lookup type. Many thanks to Ross Poulton for the proposal and implementation on all built-in database backends..
git-svn-id: http://code.djangoproject.com/svn/django/trunk@9818 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
0326574d0e
commit
addd3df3bd
3
AUTHORS
3
AUTHORS
|
@ -318,9 +318,10 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Michael Placentra II <someone@michaelplacentra2.net>
|
Michael Placentra II <someone@michaelplacentra2.net>
|
||||||
Luke Plant <http://lukeplant.me.uk/>
|
Luke Plant <http://lukeplant.me.uk/>
|
||||||
plisk
|
plisk
|
||||||
Mihai Preda <mihai_preda@yahoo.com>
|
|
||||||
Daniel Poelzleithner <http://poelzi.org/>
|
Daniel Poelzleithner <http://poelzi.org/>
|
||||||
polpak@yahoo.com
|
polpak@yahoo.com
|
||||||
|
Ross Poulton <ross@rossp.org>
|
||||||
|
Mihai Preda <mihai_preda@yahoo.com>
|
||||||
Matthias Pronk <django@masida.nl>
|
Matthias Pronk <django@masida.nl>
|
||||||
Jyrki Pulliainen <jyrki.pulliainen@gmail.com>
|
Jyrki Pulliainen <jyrki.pulliainen@gmail.com>
|
||||||
Thejaswi Puthraya <thejaswi.puthraya@gmail.com>
|
Thejaswi Puthraya <thejaswi.puthraya@gmail.com>
|
||||||
|
|
|
@ -116,7 +116,12 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
class DatabaseOperations(BaseDatabaseOperations):
|
class DatabaseOperations(BaseDatabaseOperations):
|
||||||
def date_extract_sql(self, lookup_type, field_name):
|
def date_extract_sql(self, lookup_type, field_name):
|
||||||
# http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
|
# http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
|
||||||
return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name)
|
if lookup_type == 'week_day':
|
||||||
|
# DAYOFWEEK() returns an integer, 1-7, Sunday=1.
|
||||||
|
# Note: WEEKDAY() returns 0-6, Monday=0.
|
||||||
|
return "DAYOFWEEK(%s)" % field_name
|
||||||
|
else:
|
||||||
|
return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name)
|
||||||
|
|
||||||
def date_trunc_sql(self, lookup_type, field_name):
|
def date_trunc_sql(self, lookup_type, field_name):
|
||||||
fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
|
fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
|
||||||
|
|
|
@ -72,7 +72,11 @@ WHEN (new.%(col_name)s IS NULL)
|
||||||
|
|
||||||
def date_extract_sql(self, lookup_type, field_name):
|
def date_extract_sql(self, lookup_type, field_name):
|
||||||
# http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163
|
# http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163
|
||||||
return "EXTRACT(%s FROM %s)" % (lookup_type, field_name)
|
if lookup_type == 'week_day':
|
||||||
|
# TO_CHAR(field, 'D') returns an integer from 1-7, where 1=Sunday.
|
||||||
|
return "TO_CHAR(%s, 'D')" % field_name
|
||||||
|
else:
|
||||||
|
return "EXTRACT(%s FROM %s)" % (lookup_type, field_name)
|
||||||
|
|
||||||
def date_trunc_sql(self, lookup_type, field_name):
|
def date_trunc_sql(self, lookup_type, field_name):
|
||||||
# Oracle uses TRUNC() for both dates and numbers.
|
# Oracle uses TRUNC() for both dates and numbers.
|
||||||
|
@ -268,9 +272,11 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
self.connection = Database.connect(conn_string, **self.options)
|
self.connection = Database.connect(conn_string, **self.options)
|
||||||
cursor = FormatStylePlaceholderCursor(self.connection)
|
cursor = FormatStylePlaceholderCursor(self.connection)
|
||||||
# Set oracle date to ansi date format. This only needs to execute
|
# Set oracle date to ansi date format. This only needs to execute
|
||||||
# once when we create a new connection.
|
# once when we create a new connection. We also set the Territory
|
||||||
|
# to 'AMERICA' which forces Sunday to evaluate to a '1' in TO_CHAR().
|
||||||
cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' "
|
cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' "
|
||||||
"NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'")
|
"NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF' "
|
||||||
|
"NLS_TERRITORY = 'AMERICA'")
|
||||||
try:
|
try:
|
||||||
self.oracle_version = int(self.connection.version.split('.')[0])
|
self.oracle_version = int(self.connection.version.split('.')[0])
|
||||||
# There's no way for the DatabaseOperations class to know the
|
# There's no way for the DatabaseOperations class to know the
|
||||||
|
|
|
@ -26,7 +26,12 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
|
|
||||||
def date_extract_sql(self, lookup_type, field_name):
|
def date_extract_sql(self, lookup_type, field_name):
|
||||||
# http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
|
# http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
|
||||||
return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name)
|
if lookup_type == 'week_day':
|
||||||
|
# Using EXTRACT(), PostgreSQL days are indexed as Sunday=0, Saturday=6.
|
||||||
|
# If we instead us TO_CHAR, they're indexed with Sunday=1, Saturday=7
|
||||||
|
return "TO_CHAR(%s, 'D')" % field_name
|
||||||
|
else:
|
||||||
|
return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name)
|
||||||
|
|
||||||
def date_trunc_sql(self, lookup_type, field_name):
|
def date_trunc_sql(self, lookup_type, field_name):
|
||||||
# http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
|
# http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
|
||||||
|
|
|
@ -207,7 +207,10 @@ def _sqlite_extract(lookup_type, dt):
|
||||||
dt = util.typecast_timestamp(dt)
|
dt = util.typecast_timestamp(dt)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
return None
|
return None
|
||||||
return unicode(getattr(dt, lookup_type))
|
if lookup_type == 'week_day':
|
||||||
|
return unicode((dt.isoweekday() % 7) + 1)
|
||||||
|
else:
|
||||||
|
return unicode(getattr(dt, lookup_type))
|
||||||
|
|
||||||
def _sqlite_date_trunc(lookup_type, dt):
|
def _sqlite_date_trunc(lookup_type, dt):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -201,7 +201,7 @@ class Field(object):
|
||||||
sql, params = value.as_sql()
|
sql, params = value.as_sql()
|
||||||
return QueryWrapper(('(%s)' % sql), params)
|
return QueryWrapper(('(%s)' % sql), params)
|
||||||
|
|
||||||
if lookup_type in ('regex', 'iregex', 'month', 'day', 'search'):
|
if lookup_type in ('regex', 'iregex', 'month', 'day', 'week_day', 'search'):
|
||||||
return [value]
|
return [value]
|
||||||
elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
|
elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
|
||||||
return [self.get_db_prep_value(value)]
|
return [self.get_db_prep_value(value)]
|
||||||
|
@ -490,9 +490,9 @@ class DateField(Field):
|
||||||
curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False))
|
curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False))
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value):
|
def get_db_prep_lookup(self, lookup_type, value):
|
||||||
# For "__month" and "__day" lookups, convert the value to a string so
|
# For "__month", "__day", and "__week_day" lookups, convert the value
|
||||||
# the database backend always sees a consistent type.
|
# to a string so the database backend always sees a consistent type.
|
||||||
if lookup_type in ('month', 'day'):
|
if lookup_type in ('month', 'day', 'week_day'):
|
||||||
return [force_unicode(value)]
|
return [force_unicode(value)]
|
||||||
return super(DateField, self).get_db_prep_lookup(lookup_type, value)
|
return super(DateField, self).get_db_prep_lookup(lookup_type, value)
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import re
|
||||||
QUERY_TERMS = dict([(x, None) for x in (
|
QUERY_TERMS = dict([(x, None) for x in (
|
||||||
'exact', 'iexact', 'contains', 'icontains', 'gt', 'gte', 'lt', 'lte', 'in',
|
'exact', 'iexact', 'contains', 'icontains', 'gt', 'gte', 'lt', 'lte', 'in',
|
||||||
'startswith', 'istartswith', 'endswith', 'iendswith', 'range', 'year',
|
'startswith', 'istartswith', 'endswith', 'iendswith', 'range', 'year',
|
||||||
'month', 'day', 'isnull', 'search', 'regex', 'iregex',
|
'month', 'day', 'week_day', 'isnull', 'search', 'regex', 'iregex',
|
||||||
)])
|
)])
|
||||||
|
|
||||||
# Size of each "chunk" for get_iterator calls.
|
# Size of each "chunk" for get_iterator calls.
|
||||||
|
|
|
@ -174,9 +174,9 @@ class WhereNode(tree.Node):
|
||||||
params)
|
params)
|
||||||
elif lookup_type in ('range', 'year'):
|
elif lookup_type in ('range', 'year'):
|
||||||
return ('%s BETWEEN %%s and %%s' % field_sql, params)
|
return ('%s BETWEEN %%s and %%s' % field_sql, params)
|
||||||
elif lookup_type in ('month', 'day'):
|
elif lookup_type in ('month', 'day', 'week_day'):
|
||||||
return ('%s = %%s' % connection.ops.date_extract_sql(lookup_type,
|
return ('%s = %%s' % connection.ops.date_extract_sql(lookup_type, field_sql),
|
||||||
field_sql), params)
|
params)
|
||||||
elif lookup_type == 'isnull':
|
elif lookup_type == 'isnull':
|
||||||
return ('%s IS %sNULL' % (field_sql,
|
return ('%s IS %sNULL' % (field_sql,
|
||||||
(not value_annot and 'NOT ' or '')), ())
|
(not value_annot and 'NOT ' or '')), ())
|
||||||
|
|
|
@ -1344,6 +1344,27 @@ SQL equivalent::
|
||||||
Note this will match any record with a pub_date on the third day of the month,
|
Note this will match any record with a pub_date on the third day of the month,
|
||||||
such as January 3, July 3, etc.
|
such as January 3, July 3, etc.
|
||||||
|
|
||||||
|
week_day
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
.. versionadded:: 1.1
|
||||||
|
|
||||||
|
For date/datetime fields, a 'day of the week' match.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
Entry.objects.filter(pub_date__week_day=2)
|
||||||
|
|
||||||
|
SQL equivalent::
|
||||||
|
|
||||||
|
SELECT ... WHERE EXTRACT('dow' FROM pub_date) = '2';
|
||||||
|
|
||||||
|
(The exact SQL syntax varies for each database engine.)
|
||||||
|
|
||||||
|
Note this will match any record with a pub_date that falls on a Monday (day 2
|
||||||
|
of the week), regardless of the month or year in which it occurs. Week days
|
||||||
|
are indexed with day 1 being Sunday and day 7 being Saturday.
|
||||||
|
|
||||||
isnull
|
isnull
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,8 @@ datetime.datetime(2005, 7, 28, 0, 0)
|
||||||
<Article: Area woman programs in Python>
|
<Article: Area woman programs in Python>
|
||||||
>>> Article.objects.get(pub_date__year=2005, pub_date__month=7, pub_date__day=28)
|
>>> Article.objects.get(pub_date__year=2005, pub_date__month=7, pub_date__day=28)
|
||||||
<Article: Area woman programs in Python>
|
<Article: Area woman programs in Python>
|
||||||
|
>>> Article.objects.get(pub_date__week_day=5)
|
||||||
|
<Article: Area woman programs in Python>
|
||||||
|
|
||||||
# The "__exact" lookup type can be omitted, as a shortcut.
|
# The "__exact" lookup type can be omitted, as a shortcut.
|
||||||
>>> Article.objects.get(id=1)
|
>>> Article.objects.get(id=1)
|
||||||
|
@ -88,6 +90,11 @@ datetime.datetime(2005, 7, 28, 0, 0)
|
||||||
>>> Article.objects.filter(pub_date__year=2005, pub_date__month=7)
|
>>> Article.objects.filter(pub_date__year=2005, pub_date__month=7)
|
||||||
[<Article: Area woman programs in Python>]
|
[<Article: Area woman programs in Python>]
|
||||||
|
|
||||||
|
>>> Article.objects.filter(pub_date__week_day=5)
|
||||||
|
[<Article: Area woman programs in Python>]
|
||||||
|
>>> Article.objects.filter(pub_date__week_day=6)
|
||||||
|
[]
|
||||||
|
|
||||||
# Django raises an Article.DoesNotExist exception for get() if the parameters
|
# Django raises an Article.DoesNotExist exception for get() if the parameters
|
||||||
# don't match any object.
|
# don't match any object.
|
||||||
>>> Article.objects.get(id__exact=2)
|
>>> Article.objects.get(id__exact=2)
|
||||||
|
@ -100,6 +107,11 @@ Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
DoesNotExist: Article matching query does not exist.
|
DoesNotExist: Article matching query does not exist.
|
||||||
|
|
||||||
|
>>> Article.objects.get(pub_date__week_day=6)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
DoesNotExist: Article matching query does not exist.
|
||||||
|
|
||||||
# Lookup by a primary key is the most common case, so Django provides a
|
# Lookup by a primary key is the most common case, so Django provides a
|
||||||
# shortcut for primary-key exact lookups.
|
# shortcut for primary-key exact lookups.
|
||||||
# The following is identical to articles.get(id=1).
|
# The following is identical to articles.get(id=1).
|
||||||
|
|
Loading…
Reference in New Issue