diff options
| author | Sigurd Ljødal <sigurd@ljodal.no> | 2017-09-28 22:39:03 +0200 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2018-01-27 09:59:13 -0500 |
| commit | a455e732a0011dfbd15eddaa4fe60cb9439326e0 (patch) | |
| tree | 1df72fb36c377ae630e1bbc8a588662f8f3cb46f /django/db | |
| parent | f229049d6cd186025f4033dc47608b0c9731e882 (diff) | |
Fixed #28650 -- Added TruncWeek database function.
Diffstat (limited to 'django/db')
| -rw-r--r-- | django/db/backends/mysql/operations.py | 10 | ||||
| -rw-r--r-- | django/db/backends/oracle/operations.py | 4 | ||||
| -rw-r--r-- | django/db/backends/sqlite3/base.py | 6 | ||||
| -rw-r--r-- | django/db/models/functions/__init__.py | 4 | ||||
| -rw-r--r-- | django/db/models/functions/datetime.py | 8 | ||||
| -rw-r--r-- | django/db/models/query.py | 8 |
6 files changed, 33 insertions, 7 deletions
diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py index ad4c13652e..2961d6449b 100644 --- a/django/db/backends/mysql/operations.py +++ b/django/db/backends/mysql/operations.py @@ -53,6 +53,10 @@ class DatabaseOperations(BaseDatabaseOperations): return "MAKEDATE(YEAR(%s), 1) + INTERVAL QUARTER(%s) QUARTER - INTERVAL 1 QUARTER" % ( field_name, field_name ) + elif lookup_type == 'week': + return "DATE_SUB(%s, INTERVAL WEEKDAY(%s) DAY)" % ( + field_name, field_name + ) else: return "DATE(%s)" % (field_name) @@ -84,6 +88,12 @@ class DatabaseOperations(BaseDatabaseOperations): "INTERVAL QUARTER({field_name}) QUARTER - " + "INTERVAL 1 QUARTER, '%%Y-%%m-01 00:00:00') AS DATETIME)" ).format(field_name=field_name) + if lookup_type == 'week': + return ( + "CAST(DATE_FORMAT(DATE_SUB({field_name}, " + "INTERVAL WEEKDAY({field_name}) DAY), " + "'%%Y-%%m-%%d 00:00:00') AS DATETIME)" + ).format(field_name=field_name) try: i = fields.index(lookup_type) + 1 except ValueError: diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py index bea03e355e..748f606368 100644 --- a/django/db/backends/oracle/operations.py +++ b/django/db/backends/oracle/operations.py @@ -78,6 +78,8 @@ END; return "TRUNC(%s, '%s')" % (field_name, lookup_type.upper()) elif lookup_type == 'quarter': return "TRUNC(%s, 'Q')" % field_name + elif lookup_type == 'week': + return "TRUNC(%s, 'IW')" % field_name else: return "TRUNC(%s)" % field_name @@ -116,6 +118,8 @@ END; sql = "TRUNC(%s, '%s')" % (field_name, lookup_type.upper()) elif lookup_type == 'quarter': sql = "TRUNC(%s, 'Q')" % field_name + elif lookup_type == 'week': + sql = "TRUNC(%s, 'IW')" % field_name elif lookup_type == 'day': sql = "TRUNC(%s)" % field_name elif lookup_type == 'hour': diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 857b050361..0971c500dd 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -335,6 +335,9 @@ def _sqlite_date_trunc(lookup_type, dt): return '%i-%02i-01' % (dt.year, month_in_quarter) elif lookup_type == 'month': return "%i-%02i-01" % (dt.year, dt.month) + elif lookup_type == 'week': + dt = dt - datetime.timedelta(days=dt.weekday()) + return "%i-%02i-%02i" % (dt.year, dt.month, dt.day) elif lookup_type == 'day': return "%i-%02i-%02i" % (dt.year, dt.month, dt.day) @@ -403,6 +406,9 @@ def _sqlite_datetime_trunc(lookup_type, dt, tzname): return '%i-%02i-01 00:00:00' % (dt.year, month_in_quarter) elif lookup_type == 'month': return "%i-%02i-01 00:00:00" % (dt.year, dt.month) + elif lookup_type == 'week': + dt = dt - datetime.timedelta(days=dt.weekday()) + return "%i-%02i-%02i 00:00:00" % (dt.year, dt.month, dt.day) elif lookup_type == 'day': return "%i-%02i-%02i 00:00:00" % (dt.year, dt.month, dt.day) elif lookup_type == 'hour': diff --git a/django/db/models/functions/__init__.py b/django/db/models/functions/__init__.py index 0680200c7a..0815628dd0 100644 --- a/django/db/models/functions/__init__.py +++ b/django/db/models/functions/__init__.py @@ -3,7 +3,7 @@ from .datetime import ( Extract, ExtractDay, ExtractHour, ExtractMinute, ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay, ExtractYear, Now, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute, TruncMonth, - TruncQuarter, TruncSecond, TruncTime, TruncYear, + TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear, ) from .text import ( Concat, ConcatPair, Length, Lower, Replace, StrIndex, Substr, Upper, @@ -21,7 +21,7 @@ __all__ = [ 'ExtractQuarter', 'ExtractSecond', 'ExtractWeek', 'ExtractWeekDay', 'ExtractYear', 'Now', 'Trunc', 'TruncDate', 'TruncDay', 'TruncHour', 'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime', - 'TruncYear', + 'TruncWeek', 'TruncYear', # text 'Concat', 'ConcatPair', 'Length', 'Lower', 'Replace', 'StrIndex', 'Substr', 'Upper', diff --git a/django/db/models/functions/datetime.py b/django/db/models/functions/datetime.py index 44bcb731e6..74b88b77ca 100644 --- a/django/db/models/functions/datetime.py +++ b/django/db/models/functions/datetime.py @@ -199,7 +199,8 @@ class TruncBase(TimezoneMixin, Transform): field.name, output_field.__class__.__name__ if has_explicit_output_field else 'DateTimeField' )) elif isinstance(field, TimeField) and ( - isinstance(output_field, DateTimeField) or copy.kind in ('year', 'quarter', 'month', 'day', 'date')): + isinstance(output_field, DateTimeField) or + copy.kind in ('year', 'quarter', 'month', 'week', 'day', 'date')): raise ValueError("Cannot truncate TimeField '%s' to %s. " % ( field.name, output_field.__class__.__name__ if has_explicit_output_field else 'DateTimeField' )) @@ -242,6 +243,11 @@ class TruncMonth(TruncBase): kind = 'month' +class TruncWeek(TruncBase): + """Truncate to midnight on the Monday of the week.""" + kind = 'week' + + class TruncDay(TruncBase): kind = 'day' diff --git a/django/db/models/query.py b/django/db/models/query.py index e17f8da1a8..44bc51d0e0 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -777,8 +777,8 @@ class QuerySet: Return a list of date objects representing all available dates for the given field_name, scoped to 'kind'. """ - assert kind in ("year", "month", "day"), \ - "'kind' must be one of 'year', 'month' or 'day'." + assert kind in ('year', 'month', 'week', 'day'), \ + "'kind' must be one of 'year', 'month', 'week', or 'day'." assert order in ('ASC', 'DESC'), \ "'order' must be either 'ASC' or 'DESC'." return self.annotate( @@ -793,8 +793,8 @@ class QuerySet: Return a list of datetime objects representing all available datetimes for the given field_name, scoped to 'kind'. """ - assert kind in ("year", "month", "day", "hour", "minute", "second"), \ - "'kind' must be one of 'year', 'month', 'day', 'hour', 'minute' or 'second'." + assert kind in ('year', 'month', 'week', 'day', 'hour', 'minute', 'second'), \ + "'kind' must be one of 'year', 'month', 'week', 'day', 'hour', 'minute', or 'second'." assert order in ('ASC', 'DESC'), \ "'order' must be either 'ASC' or 'DESC'." if settings.USE_TZ: |
