mirror of
https://github.com/django/django.git
synced 2025-01-03 15:06:09 +00:00
Fixed #30821 -- Added ExtractIsoWeekYear database function and iso_week_day lookup.
This commit is contained in:
parent
e1aa932802
commit
8ed6788aa4
@ -36,8 +36,10 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||||||
# https://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
|
# https://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
|
||||||
if lookup_type == 'week_day':
|
if lookup_type == 'week_day':
|
||||||
# DAYOFWEEK() returns an integer, 1-7, Sunday=1.
|
# DAYOFWEEK() returns an integer, 1-7, Sunday=1.
|
||||||
# Note: WEEKDAY() returns 0-6, Monday=0.
|
|
||||||
return "DAYOFWEEK(%s)" % field_name
|
return "DAYOFWEEK(%s)" % field_name
|
||||||
|
elif lookup_type == 'iso_week_day':
|
||||||
|
# WEEKDAY() returns an integer, 0-6, Monday=0.
|
||||||
|
return "WEEKDAY(%s) + 1" % field_name
|
||||||
elif lookup_type == 'week':
|
elif lookup_type == 'week':
|
||||||
# Override the value of default_week_format for consistency with
|
# Override the value of default_week_format for consistency with
|
||||||
# other database backends.
|
# other database backends.
|
||||||
|
@ -74,6 +74,8 @@ END;
|
|||||||
if lookup_type == 'week_day':
|
if lookup_type == 'week_day':
|
||||||
# TO_CHAR(field, 'D') returns an integer from 1-7, where 1=Sunday.
|
# TO_CHAR(field, 'D') returns an integer from 1-7, where 1=Sunday.
|
||||||
return "TO_CHAR(%s, 'D')" % field_name
|
return "TO_CHAR(%s, 'D')" % field_name
|
||||||
|
elif lookup_type == 'iso_week_day':
|
||||||
|
return "TO_CHAR(%s - 1, 'D')" % field_name
|
||||||
elif lookup_type == 'week':
|
elif lookup_type == 'week':
|
||||||
# IW = ISO week number
|
# IW = ISO week number
|
||||||
return "TO_CHAR(%s, 'IW')" % field_name
|
return "TO_CHAR(%s, 'IW')" % field_name
|
||||||
|
@ -32,6 +32,8 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||||||
if lookup_type == 'week_day':
|
if lookup_type == 'week_day':
|
||||||
# For consistency across backends, we return Sunday=1, Saturday=7.
|
# For consistency across backends, we return Sunday=1, Saturday=7.
|
||||||
return "EXTRACT('dow' FROM %s) + 1" % field_name
|
return "EXTRACT('dow' FROM %s) + 1" % field_name
|
||||||
|
elif lookup_type == 'iso_week_day':
|
||||||
|
return "EXTRACT('isodow' FROM %s)" % field_name
|
||||||
elif lookup_type == 'iso_year':
|
elif lookup_type == 'iso_year':
|
||||||
return "EXTRACT('isoyear' FROM %s)" % field_name
|
return "EXTRACT('isoyear' FROM %s)" % field_name
|
||||||
else:
|
else:
|
||||||
|
@ -478,6 +478,8 @@ def _sqlite_datetime_extract(lookup_type, dt, tzname=None, conn_tzname=None):
|
|||||||
return None
|
return None
|
||||||
if lookup_type == 'week_day':
|
if lookup_type == 'week_day':
|
||||||
return (dt.isoweekday() % 7) + 1
|
return (dt.isoweekday() % 7) + 1
|
||||||
|
elif lookup_type == 'iso_week_day':
|
||||||
|
return dt.isoweekday()
|
||||||
elif lookup_type == 'week':
|
elif lookup_type == 'week':
|
||||||
return dt.isocalendar()[1]
|
return dt.isocalendar()[1]
|
||||||
elif lookup_type == 'quarter':
|
elif lookup_type == 'quarter':
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
from .comparison import Cast, Coalesce, Greatest, Least, NullIf
|
from .comparison import Cast, Coalesce, Greatest, Least, NullIf
|
||||||
from .datetime import (
|
from .datetime import (
|
||||||
Extract, ExtractDay, ExtractHour, ExtractIsoYear, ExtractMinute,
|
Extract, ExtractDay, ExtractHour, ExtractIsoWeekDay, ExtractIsoYear,
|
||||||
ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay,
|
ExtractMinute, ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek,
|
||||||
ExtractYear, Now, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute,
|
ExtractWeekDay, ExtractYear, Now, Trunc, TruncDate, TruncDay, TruncHour,
|
||||||
TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear,
|
TruncMinute, TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncWeek,
|
||||||
|
TruncYear,
|
||||||
)
|
)
|
||||||
from .math import (
|
from .math import (
|
||||||
Abs, ACos, ASin, ATan, ATan2, Ceil, Cos, Cot, Degrees, Exp, Floor, Ln, Log,
|
Abs, ACos, ASin, ATan, ATan2, Ceil, Cos, Cot, Degrees, Exp, Floor, Ln, Log,
|
||||||
@ -24,11 +25,11 @@ __all__ = [
|
|||||||
'Cast', 'Coalesce', 'Greatest', 'Least', 'NullIf',
|
'Cast', 'Coalesce', 'Greatest', 'Least', 'NullIf',
|
||||||
# datetime
|
# datetime
|
||||||
'Extract', 'ExtractDay', 'ExtractHour', 'ExtractMinute', 'ExtractMonth',
|
'Extract', 'ExtractDay', 'ExtractHour', 'ExtractMinute', 'ExtractMonth',
|
||||||
'ExtractQuarter', 'ExtractSecond', 'ExtractWeek', 'ExtractWeekDay',
|
'ExtractQuarter', 'ExtractSecond', 'ExtractWeek', 'ExtractIsoWeekDay',
|
||||||
'ExtractIsoYear', 'ExtractYear', 'Now', 'Trunc', 'TruncDate', 'TruncDay',
|
'ExtractWeekDay', 'ExtractIsoYear', 'ExtractYear', 'Now', 'Trunc',
|
||||||
'TruncHour', 'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond',
|
'TruncDate', 'TruncDay', 'TruncHour', 'TruncMinute', 'TruncMonth',
|
||||||
'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime',
|
'TruncQuarter', 'TruncSecond', 'TruncMinute', 'TruncMonth', 'TruncQuarter',
|
||||||
'TruncWeek', 'TruncYear',
|
'TruncSecond', 'TruncTime', 'TruncWeek', 'TruncYear',
|
||||||
# math
|
# math
|
||||||
'Abs', 'ACos', 'ASin', 'ATan', 'ATan2', 'Ceil', 'Cos', 'Cot', 'Degrees',
|
'Abs', 'ACos', 'ASin', 'ATan', 'ATan2', 'Ceil', 'Cos', 'Cot', 'Degrees',
|
||||||
'Exp', 'Floor', 'Ln', 'Log', 'Mod', 'Pi', 'Power', 'Radians', 'Round',
|
'Exp', 'Floor', 'Ln', 'Log', 'Mod', 'Pi', 'Power', 'Radians', 'Round',
|
||||||
|
@ -75,7 +75,7 @@ class Extract(TimezoneMixin, Transform):
|
|||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
isinstance(field, DurationField) and
|
isinstance(field, DurationField) and
|
||||||
copy.lookup_name in ('year', 'iso_year', 'month', 'week', 'week_day', 'quarter')
|
copy.lookup_name in ('year', 'iso_year', 'month', 'week', 'week_day', 'iso_week_day', 'quarter')
|
||||||
):
|
):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Cannot extract component '%s' from DurationField '%s'."
|
"Cannot extract component '%s' from DurationField '%s'."
|
||||||
@ -118,6 +118,11 @@ class ExtractWeekDay(Extract):
|
|||||||
lookup_name = 'week_day'
|
lookup_name = 'week_day'
|
||||||
|
|
||||||
|
|
||||||
|
class ExtractIsoWeekDay(Extract):
|
||||||
|
"""Return Monday=1 through Sunday=7, based on ISO-8601."""
|
||||||
|
lookup_name = 'iso_week_day'
|
||||||
|
|
||||||
|
|
||||||
class ExtractQuarter(Extract):
|
class ExtractQuarter(Extract):
|
||||||
lookup_name = 'quarter'
|
lookup_name = 'quarter'
|
||||||
|
|
||||||
@ -138,6 +143,7 @@ DateField.register_lookup(ExtractYear)
|
|||||||
DateField.register_lookup(ExtractMonth)
|
DateField.register_lookup(ExtractMonth)
|
||||||
DateField.register_lookup(ExtractDay)
|
DateField.register_lookup(ExtractDay)
|
||||||
DateField.register_lookup(ExtractWeekDay)
|
DateField.register_lookup(ExtractWeekDay)
|
||||||
|
DateField.register_lookup(ExtractIsoWeekDay)
|
||||||
DateField.register_lookup(ExtractWeek)
|
DateField.register_lookup(ExtractWeek)
|
||||||
DateField.register_lookup(ExtractIsoYear)
|
DateField.register_lookup(ExtractIsoYear)
|
||||||
DateField.register_lookup(ExtractQuarter)
|
DateField.register_lookup(ExtractQuarter)
|
||||||
|
@ -205,6 +205,7 @@ Given the datetime ``2015-06-15 23:30:01.000321+00:00``, the built-in
|
|||||||
* "day": 15
|
* "day": 15
|
||||||
* "week": 25
|
* "week": 25
|
||||||
* "week_day": 2
|
* "week_day": 2
|
||||||
|
* "iso_week_day": 1
|
||||||
* "hour": 23
|
* "hour": 23
|
||||||
* "minute": 30
|
* "minute": 30
|
||||||
* "second": 1
|
* "second": 1
|
||||||
@ -216,6 +217,7 @@ returned when this timezone is active will be the same as above except for:
|
|||||||
|
|
||||||
* "day": 16
|
* "day": 16
|
||||||
* "week_day": 3
|
* "week_day": 3
|
||||||
|
* "iso_week_day": 2
|
||||||
* "hour": 9
|
* "hour": 9
|
||||||
|
|
||||||
.. admonition:: ``week_day`` values
|
.. admonition:: ``week_day`` values
|
||||||
@ -288,6 +290,15 @@ Usage example::
|
|||||||
|
|
||||||
.. attribute:: lookup_name = 'week_day'
|
.. attribute:: lookup_name = 'week_day'
|
||||||
|
|
||||||
|
.. class:: ExtractIsoWeekDay(expression, tzinfo=None, **extra)
|
||||||
|
|
||||||
|
.. versionadded:: 3.1
|
||||||
|
|
||||||
|
Returns the ISO-8601 week day with day 1 being Monday and day 7 being
|
||||||
|
Sunday.
|
||||||
|
|
||||||
|
.. attribute:: lookup_name = 'iso_week_day'
|
||||||
|
|
||||||
.. class:: ExtractWeek(expression, tzinfo=None, **extra)
|
.. class:: ExtractWeek(expression, tzinfo=None, **extra)
|
||||||
|
|
||||||
.. attribute:: lookup_name = 'week'
|
.. attribute:: lookup_name = 'week'
|
||||||
@ -307,7 +318,7 @@ that deal with date-parts can be used with ``DateField``::
|
|||||||
>>> from django.utils import timezone
|
>>> from django.utils import timezone
|
||||||
>>> from django.db.models.functions import (
|
>>> from django.db.models.functions import (
|
||||||
... ExtractDay, ExtractMonth, ExtractQuarter, ExtractWeek,
|
... ExtractDay, ExtractMonth, ExtractQuarter, ExtractWeek,
|
||||||
... ExtractWeekDay, ExtractIsoYear, ExtractYear,
|
... ExtractIsoWeekDay, ExtractWeekDay, ExtractIsoYear, ExtractYear,
|
||||||
... )
|
... )
|
||||||
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
|
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
|
||||||
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
|
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
|
||||||
@ -322,11 +333,13 @@ that deal with date-parts can be used with ``DateField``::
|
|||||||
... week=ExtractWeek('start_date'),
|
... week=ExtractWeek('start_date'),
|
||||||
... day=ExtractDay('start_date'),
|
... day=ExtractDay('start_date'),
|
||||||
... weekday=ExtractWeekDay('start_date'),
|
... weekday=ExtractWeekDay('start_date'),
|
||||||
... ).values('year', 'isoyear', 'quarter', 'month', 'week', 'day', 'weekday').get(
|
... isoweekday=ExtractIsoWeekDay('start_date'),
|
||||||
... end_date__year=ExtractYear('start_date'),
|
... ).values(
|
||||||
... )
|
... 'year', 'isoyear', 'quarter', 'month', 'week', 'day', 'weekday',
|
||||||
|
... 'isoweekday',
|
||||||
|
... ).get(end_date__year=ExtractYear('start_date'))
|
||||||
{'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
|
{'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
|
||||||
'day': 15, 'weekday': 2}
|
'day': 15, 'weekday': 2, 'isoweekday': 1}
|
||||||
|
|
||||||
``DateTimeField`` extracts
|
``DateTimeField`` extracts
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
@ -356,8 +369,8 @@ Each class is also a ``Transform`` registered on ``DateTimeField`` as
|
|||||||
>>> from django.utils import timezone
|
>>> from django.utils import timezone
|
||||||
>>> from django.db.models.functions import (
|
>>> from django.db.models.functions import (
|
||||||
... ExtractDay, ExtractHour, ExtractMinute, ExtractMonth,
|
... ExtractDay, ExtractHour, ExtractMinute, ExtractMonth,
|
||||||
... ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay,
|
... ExtractQuarter, ExtractSecond, ExtractWeek, ExtractIsoWeekDay,
|
||||||
... ExtractIsoYear, ExtractYear,
|
... ExtractWeekDay, ExtractIsoYear, ExtractYear,
|
||||||
... )
|
... )
|
||||||
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
|
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
|
||||||
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
|
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
|
||||||
@ -372,15 +385,17 @@ Each class is also a ``Transform`` registered on ``DateTimeField`` as
|
|||||||
... week=ExtractWeek('start_datetime'),
|
... week=ExtractWeek('start_datetime'),
|
||||||
... day=ExtractDay('start_datetime'),
|
... day=ExtractDay('start_datetime'),
|
||||||
... weekday=ExtractWeekDay('start_datetime'),
|
... weekday=ExtractWeekDay('start_datetime'),
|
||||||
|
... isoweekday=ExtractIsoWeekDay('start_datetime'),
|
||||||
... hour=ExtractHour('start_datetime'),
|
... hour=ExtractHour('start_datetime'),
|
||||||
... minute=ExtractMinute('start_datetime'),
|
... minute=ExtractMinute('start_datetime'),
|
||||||
... second=ExtractSecond('start_datetime'),
|
... second=ExtractSecond('start_datetime'),
|
||||||
... ).values(
|
... ).values(
|
||||||
... 'year', 'isoyear', 'month', 'week', 'day',
|
... 'year', 'isoyear', 'month', 'week', 'day',
|
||||||
... 'weekday', 'hour', 'minute', 'second',
|
... 'weekday', 'isoweekday', 'hour', 'minute', 'second',
|
||||||
... ).get(end_datetime__year=ExtractYear('start_datetime'))
|
... ).get(end_datetime__year=ExtractYear('start_datetime'))
|
||||||
{'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
|
{'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
|
||||||
'day': 15, 'weekday': 2, 'hour': 23, 'minute': 30, 'second': 1}
|
'day': 15, 'weekday': 2, 'isoweekday': 1, 'hour': 23, 'minute': 30,
|
||||||
|
'second': 1}
|
||||||
|
|
||||||
When :setting:`USE_TZ` is ``True`` then datetimes are stored in the database
|
When :setting:`USE_TZ` is ``True`` then datetimes are stored in the database
|
||||||
in UTC. If a different timezone is active in Django, the datetime is converted
|
in UTC. If a different timezone is active in Django, the datetime is converted
|
||||||
@ -394,11 +409,12 @@ values that are returned::
|
|||||||
... Experiment.objects.annotate(
|
... Experiment.objects.annotate(
|
||||||
... day=ExtractDay('start_datetime'),
|
... day=ExtractDay('start_datetime'),
|
||||||
... weekday=ExtractWeekDay('start_datetime'),
|
... weekday=ExtractWeekDay('start_datetime'),
|
||||||
|
... isoweekday=ExtractIsoWeekDay('start_datetime'),
|
||||||
... hour=ExtractHour('start_datetime'),
|
... hour=ExtractHour('start_datetime'),
|
||||||
... ).values('day', 'weekday', 'hour').get(
|
... ).values('day', 'weekday', 'isoweekday', 'hour').get(
|
||||||
... end_datetime__year=ExtractYear('start_datetime'),
|
... end_datetime__year=ExtractYear('start_datetime'),
|
||||||
... )
|
... )
|
||||||
{'day': 16, 'weekday': 3, 'hour': 9}
|
{'day': 16, 'weekday': 3, 'isoweekday': 2, 'hour': 9}
|
||||||
|
|
||||||
Explicitly passing the timezone to the ``Extract`` function behaves in the same
|
Explicitly passing the timezone to the ``Extract`` function behaves in the same
|
||||||
way, and takes priority over an active timezone::
|
way, and takes priority over an active timezone::
|
||||||
@ -408,11 +424,12 @@ way, and takes priority over an active timezone::
|
|||||||
>>> Experiment.objects.annotate(
|
>>> Experiment.objects.annotate(
|
||||||
... day=ExtractDay('start_datetime', tzinfo=melb),
|
... day=ExtractDay('start_datetime', tzinfo=melb),
|
||||||
... weekday=ExtractWeekDay('start_datetime', tzinfo=melb),
|
... weekday=ExtractWeekDay('start_datetime', tzinfo=melb),
|
||||||
|
... isoweekday=ExtractIsoWeekDay('start_datetime', tzinfo=melb),
|
||||||
... hour=ExtractHour('start_datetime', tzinfo=melb),
|
... hour=ExtractHour('start_datetime', tzinfo=melb),
|
||||||
... ).values('day', 'weekday', 'hour').get(
|
... ).values('day', 'weekday', 'isoweekday', 'hour').get(
|
||||||
... end_datetime__year=ExtractYear('start_datetime'),
|
... end_datetime__year=ExtractYear('start_datetime'),
|
||||||
... )
|
... )
|
||||||
{'day': 16, 'weekday': 3, 'hour': 9}
|
{'day': 16, 'weekday': 3, 'isoweekday': 2, 'hour': 9}
|
||||||
|
|
||||||
``Now``
|
``Now``
|
||||||
-------
|
-------
|
||||||
|
@ -3110,6 +3110,35 @@ When :setting:`USE_TZ` is ``True``, datetime fields are converted to the
|
|||||||
current time zone before filtering. This requires :ref:`time zone definitions
|
current time zone before filtering. This requires :ref:`time zone definitions
|
||||||
in the database <database-time-zone-definitions>`.
|
in the database <database-time-zone-definitions>`.
|
||||||
|
|
||||||
|
.. fieldlookup:: iso_week_day
|
||||||
|
|
||||||
|
``iso_week_day``
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. versionadded:: 3.1
|
||||||
|
|
||||||
|
For date and datetime fields, an exact ISO 8601 day of the week match. Allows
|
||||||
|
chaining additional field lookups.
|
||||||
|
|
||||||
|
Takes an integer value representing the day of the week from 1 (Monday) to 7
|
||||||
|
(Sunday).
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
Entry.objects.filter(pub_date__iso_week_day=1)
|
||||||
|
Entry.objects.filter(pub_date__iso_week_day__gte=1)
|
||||||
|
|
||||||
|
(No equivalent SQL code fragment is included for this lookup because
|
||||||
|
implementation of the relevant query varies among different database engines.)
|
||||||
|
|
||||||
|
Note this will match any record with a ``pub_date`` that falls on a Monday (day
|
||||||
|
1 of the week), regardless of the month or year in which it occurs. Week days
|
||||||
|
are indexed with day 1 being Monday and day 7 being Sunday.
|
||||||
|
|
||||||
|
When :setting:`USE_TZ` is ``True``, datetime fields are converted to the
|
||||||
|
current time zone before filtering. This requires :ref:`time zone definitions
|
||||||
|
in the database <database-time-zone-definitions>`.
|
||||||
|
|
||||||
.. fieldlookup:: quarter
|
.. fieldlookup:: quarter
|
||||||
|
|
||||||
``quarter``
|
``quarter``
|
||||||
|
@ -160,7 +160,10 @@ Migrations
|
|||||||
Models
|
Models
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
||||||
* ...
|
* The new :class:`~django.db.models.functions.ExtractIsoWeekDay` function
|
||||||
|
extracts ISO-8601 week days from :class:`~django.db.models.DateField` and
|
||||||
|
:class:`~django.db.models.DateTimeField`, and the new :lookup:`iso_week_day`
|
||||||
|
lookup allows querying by an ISO-8601 day of week.
|
||||||
|
|
||||||
Pagination
|
Pagination
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
@ -8,10 +8,11 @@ from django.db.models import (
|
|||||||
TimeField,
|
TimeField,
|
||||||
)
|
)
|
||||||
from django.db.models.functions import (
|
from django.db.models.functions import (
|
||||||
Extract, ExtractDay, ExtractHour, ExtractIsoYear, ExtractMinute,
|
Extract, ExtractDay, ExtractHour, ExtractIsoWeekDay, ExtractIsoYear,
|
||||||
ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay,
|
ExtractMinute, ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek,
|
||||||
ExtractYear, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute,
|
ExtractWeekDay, ExtractYear, Trunc, TruncDate, TruncDay, TruncHour,
|
||||||
TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear,
|
TruncMinute, TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncWeek,
|
||||||
|
TruncYear,
|
||||||
)
|
)
|
||||||
from django.test import (
|
from django.test import (
|
||||||
TestCase, override_settings, skipIfDBFeature, skipUnlessDBFeature,
|
TestCase, override_settings, skipIfDBFeature, skipUnlessDBFeature,
|
||||||
@ -217,6 +218,16 @@ class DateFunctionTests(TestCase):
|
|||||||
],
|
],
|
||||||
lambda m: (m.start_datetime, m.extracted)
|
lambda m: (m.start_datetime, m.extracted)
|
||||||
)
|
)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
DTModel.objects.annotate(
|
||||||
|
extracted=Extract('start_datetime', 'iso_week_day'),
|
||||||
|
).order_by('start_datetime'),
|
||||||
|
[
|
||||||
|
(start_datetime, start_datetime.isoweekday()),
|
||||||
|
(end_datetime, end_datetime.isoweekday()),
|
||||||
|
],
|
||||||
|
lambda m: (m.start_datetime, m.extracted)
|
||||||
|
)
|
||||||
self.assertQuerysetEqual(
|
self.assertQuerysetEqual(
|
||||||
DTModel.objects.annotate(extracted=Extract('start_datetime', 'hour')).order_by('start_datetime'),
|
DTModel.objects.annotate(extracted=Extract('start_datetime', 'hour')).order_by('start_datetime'),
|
||||||
[(start_datetime, start_datetime.hour), (end_datetime, end_datetime.hour)],
|
[(start_datetime, start_datetime.hour), (end_datetime, end_datetime.hour)],
|
||||||
@ -275,7 +286,10 @@ class DateFunctionTests(TestCase):
|
|||||||
|
|
||||||
def test_extract_duration_unsupported_lookups(self):
|
def test_extract_duration_unsupported_lookups(self):
|
||||||
msg = "Cannot extract component '%s' from DurationField 'duration'."
|
msg = "Cannot extract component '%s' from DurationField 'duration'."
|
||||||
for lookup in ('year', 'iso_year', 'month', 'week', 'week_day', 'quarter'):
|
for lookup in (
|
||||||
|
'year', 'iso_year', 'month', 'week', 'week_day', 'iso_week_day',
|
||||||
|
'quarter',
|
||||||
|
):
|
||||||
with self.subTest(lookup):
|
with self.subTest(lookup):
|
||||||
with self.assertRaisesMessage(ValueError, msg % lookup):
|
with self.assertRaisesMessage(ValueError, msg % lookup):
|
||||||
DTModel.objects.annotate(extracted=Extract('duration', lookup))
|
DTModel.objects.annotate(extracted=Extract('duration', lookup))
|
||||||
@ -499,6 +513,41 @@ class DateFunctionTests(TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(DTModel.objects.filter(start_datetime__week_day=ExtractWeekDay('start_datetime')).count(), 2)
|
self.assertEqual(DTModel.objects.filter(start_datetime__week_day=ExtractWeekDay('start_datetime')).count(), 2)
|
||||||
|
|
||||||
|
def test_extract_iso_weekday_func(self):
|
||||||
|
start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
|
||||||
|
end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)
|
||||||
|
if settings.USE_TZ:
|
||||||
|
start_datetime = timezone.make_aware(start_datetime, is_dst=False)
|
||||||
|
end_datetime = timezone.make_aware(end_datetime, is_dst=False)
|
||||||
|
self.create_model(start_datetime, end_datetime)
|
||||||
|
self.create_model(end_datetime, start_datetime)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
DTModel.objects.annotate(
|
||||||
|
extracted=ExtractIsoWeekDay('start_datetime'),
|
||||||
|
).order_by('start_datetime'),
|
||||||
|
[
|
||||||
|
(start_datetime, start_datetime.isoweekday()),
|
||||||
|
(end_datetime, end_datetime.isoweekday()),
|
||||||
|
],
|
||||||
|
lambda m: (m.start_datetime, m.extracted)
|
||||||
|
)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
DTModel.objects.annotate(
|
||||||
|
extracted=ExtractIsoWeekDay('start_date'),
|
||||||
|
).order_by('start_datetime'),
|
||||||
|
[
|
||||||
|
(start_datetime, start_datetime.isoweekday()),
|
||||||
|
(end_datetime, end_datetime.isoweekday()),
|
||||||
|
],
|
||||||
|
lambda m: (m.start_datetime, m.extracted)
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
DTModel.objects.filter(
|
||||||
|
start_datetime__week_day=ExtractWeekDay('start_datetime'),
|
||||||
|
).count(),
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
|
||||||
def test_extract_hour_func(self):
|
def test_extract_hour_func(self):
|
||||||
start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
|
start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
|
||||||
end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)
|
end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)
|
||||||
@ -1005,6 +1054,8 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
|
|||||||
isoyear=ExtractIsoYear('start_datetime', tzinfo=melb),
|
isoyear=ExtractIsoYear('start_datetime', tzinfo=melb),
|
||||||
weekday=ExtractWeekDay('start_datetime'),
|
weekday=ExtractWeekDay('start_datetime'),
|
||||||
weekday_melb=ExtractWeekDay('start_datetime', tzinfo=melb),
|
weekday_melb=ExtractWeekDay('start_datetime', tzinfo=melb),
|
||||||
|
isoweekday=ExtractIsoWeekDay('start_datetime'),
|
||||||
|
isoweekday_melb=ExtractIsoWeekDay('start_datetime', tzinfo=melb),
|
||||||
quarter=ExtractQuarter('start_datetime', tzinfo=melb),
|
quarter=ExtractQuarter('start_datetime', tzinfo=melb),
|
||||||
hour=ExtractHour('start_datetime'),
|
hour=ExtractHour('start_datetime'),
|
||||||
hour_melb=ExtractHour('start_datetime', tzinfo=melb),
|
hour_melb=ExtractHour('start_datetime', tzinfo=melb),
|
||||||
@ -1020,6 +1071,8 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
|
|||||||
self.assertEqual(utc_model.isoyear, 2015)
|
self.assertEqual(utc_model.isoyear, 2015)
|
||||||
self.assertEqual(utc_model.weekday, 2)
|
self.assertEqual(utc_model.weekday, 2)
|
||||||
self.assertEqual(utc_model.weekday_melb, 3)
|
self.assertEqual(utc_model.weekday_melb, 3)
|
||||||
|
self.assertEqual(utc_model.isoweekday, 1)
|
||||||
|
self.assertEqual(utc_model.isoweekday_melb, 2)
|
||||||
self.assertEqual(utc_model.quarter, 2)
|
self.assertEqual(utc_model.quarter, 2)
|
||||||
self.assertEqual(utc_model.hour, 23)
|
self.assertEqual(utc_model.hour, 23)
|
||||||
self.assertEqual(utc_model.hour_melb, 9)
|
self.assertEqual(utc_model.hour_melb, 9)
|
||||||
@ -1035,8 +1088,10 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests):
|
|||||||
self.assertEqual(melb_model.week, 25)
|
self.assertEqual(melb_model.week, 25)
|
||||||
self.assertEqual(melb_model.isoyear, 2015)
|
self.assertEqual(melb_model.isoyear, 2015)
|
||||||
self.assertEqual(melb_model.weekday, 3)
|
self.assertEqual(melb_model.weekday, 3)
|
||||||
|
self.assertEqual(melb_model.isoweekday, 2)
|
||||||
self.assertEqual(melb_model.quarter, 2)
|
self.assertEqual(melb_model.quarter, 2)
|
||||||
self.assertEqual(melb_model.weekday_melb, 3)
|
self.assertEqual(melb_model.weekday_melb, 3)
|
||||||
|
self.assertEqual(melb_model.isoweekday_melb, 2)
|
||||||
self.assertEqual(melb_model.hour, 9)
|
self.assertEqual(melb_model.hour, 9)
|
||||||
self.assertEqual(melb_model.hour_melb, 9)
|
self.assertEqual(melb_model.hour_melb, 9)
|
||||||
|
|
||||||
|
@ -153,6 +153,7 @@ class LegacyDatabaseTests(TestCase):
|
|||||||
self.assertEqual(Event.objects.filter(dt__month=1).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__month=1).count(), 2)
|
||||||
self.assertEqual(Event.objects.filter(dt__day=1).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__day=1).count(), 2)
|
||||||
self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2)
|
||||||
|
self.assertEqual(Event.objects.filter(dt__iso_week_day=6).count(), 2)
|
||||||
self.assertEqual(Event.objects.filter(dt__hour=1).count(), 1)
|
self.assertEqual(Event.objects.filter(dt__hour=1).count(), 1)
|
||||||
self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
|
||||||
self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)
|
||||||
@ -366,6 +367,7 @@ class NewDatabaseTests(TestCase):
|
|||||||
self.assertEqual(Event.objects.filter(dt__month=1).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__month=1).count(), 2)
|
||||||
self.assertEqual(Event.objects.filter(dt__day=1).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__day=1).count(), 2)
|
||||||
self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 2)
|
||||||
|
self.assertEqual(Event.objects.filter(dt__iso_week_day=6).count(), 2)
|
||||||
self.assertEqual(Event.objects.filter(dt__hour=1).count(), 1)
|
self.assertEqual(Event.objects.filter(dt__hour=1).count(), 1)
|
||||||
self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
|
||||||
self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)
|
||||||
@ -381,6 +383,7 @@ class NewDatabaseTests(TestCase):
|
|||||||
self.assertEqual(Event.objects.filter(dt__month=1).count(), 1)
|
self.assertEqual(Event.objects.filter(dt__month=1).count(), 1)
|
||||||
self.assertEqual(Event.objects.filter(dt__day=1).count(), 1)
|
self.assertEqual(Event.objects.filter(dt__day=1).count(), 1)
|
||||||
self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 1)
|
self.assertEqual(Event.objects.filter(dt__week_day=7).count(), 1)
|
||||||
|
self.assertEqual(Event.objects.filter(dt__iso_week_day=6).count(), 1)
|
||||||
self.assertEqual(Event.objects.filter(dt__hour=22).count(), 1)
|
self.assertEqual(Event.objects.filter(dt__hour=22).count(), 1)
|
||||||
self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__minute=30).count(), 2)
|
||||||
self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)
|
self.assertEqual(Event.objects.filter(dt__second=0).count(), 2)
|
||||||
|
Loading…
Reference in New Issue
Block a user