Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
django
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
django
Commits
8a4f017f
Kaydet (Commit)
8a4f017f
authored
Haz 19, 2016
tarafından
Simon Charette
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Fixed #26348 -- Added TruncTime and exposed it through the __time lookup.
Thanks Tim for the review.
üst
082c52db
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
119 additions
and
3 deletions
+119
-3
operations.py
django/db/backends/base/operations.py
+6
-0
operations.py
django/db/backends/mysql/operations.py
+5
-0
operations.py
django/db/backends/oracle/operations.py
+6
-0
operations.py
django/db/backends/postgresql/operations.py
+5
-0
base.py
django/db/backends/sqlite3/base.py
+8
-0
operations.py
django/db/backends/sqlite3/operations.py
+4
-0
__init__.py
django/db/models/functions/__init__.py
+2
-2
datetime.py
django/db/models/functions/datetime.py
+18
-0
database-functions.txt
docs/ref/models/database-functions.txt
+11
-0
querysets.txt
docs/ref/models/querysets.txt
+21
-0
1.11.txt
docs/releases/1.11.txt
+8
-0
test_datetime.py
tests/db_functions/test_datetime.py
+25
-1
No files found.
django/db/backends/base/operations.py
Dosyayı görüntüle @
8a4f017f
...
@@ -96,6 +96,12 @@ class BaseDatabaseOperations(object):
...
@@ -96,6 +96,12 @@ class BaseDatabaseOperations(object):
"""
"""
raise
NotImplementedError
(
'subclasses of BaseDatabaseOperations may require a datetime_cast_date() method'
)
raise
NotImplementedError
(
'subclasses of BaseDatabaseOperations may require a datetime_cast_date() method'
)
def
datetime_cast_time_sql
(
self
,
field_name
,
tzname
):
"""
Returns the SQL necessary to cast a datetime value to time value.
"""
raise
NotImplementedError
(
'subclasses of BaseDatabaseOperations may require a datetime_cast_time_sql() method'
)
def
datetime_extract_sql
(
self
,
lookup_type
,
field_name
,
tzname
):
def
datetime_extract_sql
(
self
,
lookup_type
,
field_name
,
tzname
):
"""
"""
Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute' or
Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute' or
...
...
django/db/backends/mysql/operations.py
Dosyayı görüntüle @
8a4f017f
...
@@ -51,6 +51,11 @@ class DatabaseOperations(BaseDatabaseOperations):
...
@@ -51,6 +51,11 @@ class DatabaseOperations(BaseDatabaseOperations):
sql
=
"DATE(
%
s)"
%
field_name
sql
=
"DATE(
%
s)"
%
field_name
return
sql
,
params
return
sql
,
params
def
datetime_cast_time_sql
(
self
,
field_name
,
tzname
):
field_name
,
params
=
self
.
_convert_field_to_tz
(
field_name
,
tzname
)
sql
=
"TIME(
%
s)"
%
field_name
return
sql
,
params
def
datetime_extract_sql
(
self
,
lookup_type
,
field_name
,
tzname
):
def
datetime_extract_sql
(
self
,
lookup_type
,
field_name
,
tzname
):
field_name
,
params
=
self
.
_convert_field_to_tz
(
field_name
,
tzname
)
field_name
,
params
=
self
.
_convert_field_to_tz
(
field_name
,
tzname
)
sql
=
self
.
date_extract_sql
(
lookup_type
,
field_name
)
sql
=
self
.
date_extract_sql
(
lookup_type
,
field_name
)
...
...
django/db/backends/oracle/operations.py
Dosyayı görüntüle @
8a4f017f
...
@@ -128,6 +128,12 @@ WHEN (new.%(col_name)s IS NULL)
...
@@ -128,6 +128,12 @@ WHEN (new.%(col_name)s IS NULL)
sql
=
'TRUNC(
%
s)'
%
field_name
sql
=
'TRUNC(
%
s)'
%
field_name
return
sql
,
[]
return
sql
,
[]
def
datetime_cast_time_sql
(
self
,
field_name
,
tzname
):
# Since `TimeField` values are stored as TIMESTAMP where only the date
# part is ignored, convert the field to the specified timezone.
field_name
=
self
.
_convert_field_to_tz
(
field_name
,
tzname
)
return
field_name
,
[]
def
datetime_extract_sql
(
self
,
lookup_type
,
field_name
,
tzname
):
def
datetime_extract_sql
(
self
,
lookup_type
,
field_name
,
tzname
):
field_name
=
self
.
_convert_field_to_tz
(
field_name
,
tzname
)
field_name
=
self
.
_convert_field_to_tz
(
field_name
,
tzname
)
sql
=
self
.
date_extract_sql
(
lookup_type
,
field_name
)
sql
=
self
.
date_extract_sql
(
lookup_type
,
field_name
)
...
...
django/db/backends/postgresql/operations.py
Dosyayı görüntüle @
8a4f017f
...
@@ -45,6 +45,11 @@ class DatabaseOperations(BaseDatabaseOperations):
...
@@ -45,6 +45,11 @@ class DatabaseOperations(BaseDatabaseOperations):
sql
=
'(
%
s)::date'
%
field_name
sql
=
'(
%
s)::date'
%
field_name
return
sql
,
params
return
sql
,
params
def
datetime_cast_time_sql
(
self
,
field_name
,
tzname
):
field_name
,
params
=
self
.
_convert_field_to_tz
(
field_name
,
tzname
)
sql
=
'(
%
s)::time'
%
field_name
return
sql
,
params
def
datetime_extract_sql
(
self
,
lookup_type
,
field_name
,
tzname
):
def
datetime_extract_sql
(
self
,
lookup_type
,
field_name
,
tzname
):
field_name
,
params
=
self
.
_convert_field_to_tz
(
field_name
,
tzname
)
field_name
,
params
=
self
.
_convert_field_to_tz
(
field_name
,
tzname
)
sql
=
self
.
date_extract_sql
(
lookup_type
,
field_name
)
sql
=
self
.
date_extract_sql
(
lookup_type
,
field_name
)
...
...
django/db/backends/sqlite3/base.py
Dosyayı görüntüle @
8a4f017f
...
@@ -210,6 +210,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
...
@@ -210,6 +210,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
conn
.
create_function
(
"django_date_extract"
,
2
,
_sqlite_date_extract
)
conn
.
create_function
(
"django_date_extract"
,
2
,
_sqlite_date_extract
)
conn
.
create_function
(
"django_date_trunc"
,
2
,
_sqlite_date_trunc
)
conn
.
create_function
(
"django_date_trunc"
,
2
,
_sqlite_date_trunc
)
conn
.
create_function
(
"django_datetime_cast_date"
,
2
,
_sqlite_datetime_cast_date
)
conn
.
create_function
(
"django_datetime_cast_date"
,
2
,
_sqlite_datetime_cast_date
)
conn
.
create_function
(
"django_datetime_cast_time"
,
2
,
_sqlite_datetime_cast_time
)
conn
.
create_function
(
"django_datetime_extract"
,
3
,
_sqlite_datetime_extract
)
conn
.
create_function
(
"django_datetime_extract"
,
3
,
_sqlite_datetime_extract
)
conn
.
create_function
(
"django_datetime_trunc"
,
3
,
_sqlite_datetime_trunc
)
conn
.
create_function
(
"django_datetime_trunc"
,
3
,
_sqlite_datetime_trunc
)
conn
.
create_function
(
"django_time_extract"
,
2
,
_sqlite_time_extract
)
conn
.
create_function
(
"django_time_extract"
,
2
,
_sqlite_time_extract
)
...
@@ -403,6 +404,13 @@ def _sqlite_datetime_cast_date(dt, tzname):
...
@@ -403,6 +404,13 @@ def _sqlite_datetime_cast_date(dt, tzname):
return
dt
.
date
()
.
isoformat
()
return
dt
.
date
()
.
isoformat
()
def
_sqlite_datetime_cast_time
(
dt
,
tzname
):
dt
=
_sqlite_datetime_parse
(
dt
,
tzname
)
if
dt
is
None
:
return
None
return
dt
.
time
()
.
isoformat
()
def
_sqlite_datetime_extract
(
lookup_type
,
dt
,
tzname
):
def
_sqlite_datetime_extract
(
lookup_type
,
dt
,
tzname
):
dt
=
_sqlite_datetime_parse
(
dt
,
tzname
)
dt
=
_sqlite_datetime_parse
(
dt
,
tzname
)
if
dt
is
None
:
if
dt
is
None
:
...
...
django/db/backends/sqlite3/operations.py
Dosyayı görüntüle @
8a4f017f
...
@@ -85,6 +85,10 @@ class DatabaseOperations(BaseDatabaseOperations):
...
@@ -85,6 +85,10 @@ class DatabaseOperations(BaseDatabaseOperations):
self
.
_require_pytz
()
self
.
_require_pytz
()
return
"django_datetime_cast_date(
%
s,
%%
s)"
%
field_name
,
[
tzname
]
return
"django_datetime_cast_date(
%
s,
%%
s)"
%
field_name
,
[
tzname
]
def
datetime_cast_time_sql
(
self
,
field_name
,
tzname
):
self
.
_require_pytz
()
return
"django_datetime_cast_time(
%
s,
%%
s)"
%
field_name
,
[
tzname
]
def
datetime_extract_sql
(
self
,
lookup_type
,
field_name
,
tzname
):
def
datetime_extract_sql
(
self
,
lookup_type
,
field_name
,
tzname
):
# Same comment as in date_extract_sql.
# Same comment as in date_extract_sql.
self
.
_require_pytz
()
self
.
_require_pytz
()
...
...
django/db/models/functions/__init__.py
Dosyayı görüntüle @
8a4f017f
...
@@ -5,7 +5,7 @@ from .base import (
...
@@ -5,7 +5,7 @@ from .base import (
from
.datetime
import
(
from
.datetime
import
(
Extract
,
ExtractDay
,
ExtractHour
,
ExtractMinute
,
ExtractMonth
,
Extract
,
ExtractDay
,
ExtractHour
,
ExtractMinute
,
ExtractMonth
,
ExtractSecond
,
ExtractWeekDay
,
ExtractYear
,
Trunc
,
TruncDate
,
TruncDay
,
ExtractSecond
,
ExtractWeekDay
,
ExtractYear
,
Trunc
,
TruncDate
,
TruncDay
,
TruncHour
,
TruncMinute
,
TruncMonth
,
TruncSecond
,
TruncYear
,
TruncHour
,
TruncMinute
,
TruncMonth
,
TruncSecond
,
Trunc
Time
,
Trunc
Year
,
)
)
__all__
=
[
__all__
=
[
...
@@ -16,5 +16,5 @@ __all__ = [
...
@@ -16,5 +16,5 @@ __all__ = [
'Extract'
,
'ExtractDay'
,
'ExtractHour'
,
'ExtractMinute'
,
'ExtractMonth'
,
'Extract'
,
'ExtractDay'
,
'ExtractHour'
,
'ExtractMinute'
,
'ExtractMonth'
,
'ExtractSecond'
,
'ExtractWeekDay'
,
'ExtractYear'
,
'ExtractSecond'
,
'ExtractWeekDay'
,
'ExtractYear'
,
'Trunc'
,
'TruncDate'
,
'TruncDay'
,
'TruncHour'
,
'TruncMinute'
,
'TruncMonth'
,
'Trunc'
,
'TruncDate'
,
'TruncDay'
,
'TruncHour'
,
'TruncMinute'
,
'TruncMonth'
,
'TruncSecond'
,
'TruncYear'
,
'TruncSecond'
,
'Trunc
Time'
,
'Trunc
Year'
,
]
]
django/db/models/functions/datetime.py
Dosyayı görüntüle @
8a4f017f
...
@@ -239,6 +239,23 @@ class TruncDate(TruncBase):
...
@@ -239,6 +239,23 @@ class TruncDate(TruncBase):
return
sql
,
lhs_params
return
sql
,
lhs_params
class
TruncTime
(
TruncBase
):
kind
=
'time'
lookup_name
=
'time'
@cached_property
def
output_field
(
self
):
return
TimeField
()
def
as_sql
(
self
,
compiler
,
connection
):
# Cast to date rather than truncate to date.
lhs
,
lhs_params
=
compiler
.
compile
(
self
.
lhs
)
tzname
=
timezone
.
get_current_timezone_name
()
if
settings
.
USE_TZ
else
None
sql
,
tz_params
=
connection
.
ops
.
datetime_cast_time_sql
(
lhs
,
tzname
)
lhs_params
.
extend
(
tz_params
)
return
sql
,
lhs_params
class
TruncHour
(
TruncBase
):
class
TruncHour
(
TruncBase
):
kind
=
'hour'
kind
=
'hour'
...
@@ -252,3 +269,4 @@ class TruncSecond(TruncBase):
...
@@ -252,3 +269,4 @@ class TruncSecond(TruncBase):
DateTimeField
.
register_lookup
(
TruncDate
)
DateTimeField
.
register_lookup
(
TruncDate
)
DateTimeField
.
register_lookup
(
TruncTime
)
docs/ref/models/database-functions.txt
Dosyayı görüntüle @
8a4f017f
...
@@ -686,6 +686,17 @@ that deal with time-parts can be used with ``TimeField``::
...
@@ -686,6 +686,17 @@ that deal with time-parts can be used with ``TimeField``::
truncate function. It's also registered as a transform on ``DateTimeField`` as
truncate function. It's also registered as a transform on ``DateTimeField`` as
``__date``.
``__date``.
.. class:: TruncTime(expression, **extra)
.. versionadded:: 1.11
.. attribute:: lookup_name = 'time'
.. attribute:: output_field = TimeField()
``TruncTime`` casts ``expression`` to a time rather than using the built-in SQL
truncate function. It's also registered as a transform on ``DateTimeField`` as
``__time``.
.. class:: TruncDay(expression, output_field=None, tzinfo=None, **extra)
.. class:: TruncDay(expression, output_field=None, tzinfo=None, **extra)
.. attribute:: kind = 'day'
.. attribute:: kind = 'day'
...
...
docs/ref/models/querysets.txt
Dosyayı görüntüle @
8a4f017f
...
@@ -2674,6 +2674,27 @@ When :setting:`USE_TZ` is ``True``, datetime fields are converted to the
...
@@ -2674,6 +2674,27 @@ 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:: time
``time``
~~~~~~~~
.. versionadded:: 1.11
For datetime fields, casts the value as time. Allows chaining additional field
lookups. Takes a :class:`datetime.time` value.
Example::
Entry.objects.filter(pub_date__time=datetime.time(14, 30))
Entry.objects.filter(pub_date__time__between=(datetime.time(8), datetime.time(17)))
(No equivalent SQL code fragment is included for this lookup because
implementation of the relevant query varies among different database engines.)
When :setting:`USE_TZ` is ``True``, fields are converted to the current time
zone before filtering.
.. fieldlookup:: hour
.. fieldlookup:: hour
``hour``
``hour``
...
...
docs/releases/1.11.txt
Dosyayı görüntüle @
8a4f017f
...
@@ -201,6 +201,10 @@ Models
...
@@ -201,6 +201,10 @@ Models
* Added support for time truncation to
* Added support for time truncation to
:class:`~django.db.models.functions.datetime.Trunc` functions.
:class:`~django.db.models.functions.datetime.Trunc` functions.
* Added the :class:`~django.db.models.functions.datetime.TruncTime` function
to truncate :class:`~django.db.models.DateTimeField` to its time component
and exposed it through the :lookup:`time` lookup.
Requests and Responses
Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~
...
@@ -273,6 +277,10 @@ Database backend API
...
@@ -273,6 +277,10 @@ Database backend API
``lookup_type`` argument can be either ``'hour'``, ``'minute'``, or
``lookup_type`` argument can be either ``'hour'``, ``'minute'``, or
``'second'``.
``'second'``.
* The ``DatabaseOperations.datetime_cast_time_sql()`` method is added to
support the :lookup:`time` lookup. It accepts a ``field_name`` and ``tzname``
arguments and returns the SQL necessary to cast a datetime value to time value.
Dropped support for PostgreSQL 9.2 and PostGIS 2.0
Dropped support for PostgreSQL 9.2 and PostGIS 2.0
--------------------------------------------------
--------------------------------------------------
...
...
tests/db_functions/test_datetime.py
Dosyayı görüntüle @
8a4f017f
...
@@ -9,7 +9,7 @@ from django.db.models import DateField, DateTimeField, IntegerField, TimeField
...
@@ -9,7 +9,7 @@ from django.db.models import DateField, DateTimeField, IntegerField, TimeField
from
django.db.models.functions
import
(
from
django.db.models.functions
import
(
Extract
,
ExtractDay
,
ExtractHour
,
ExtractMinute
,
ExtractMonth
,
Extract
,
ExtractDay
,
ExtractHour
,
ExtractMinute
,
ExtractMonth
,
ExtractSecond
,
ExtractWeekDay
,
ExtractYear
,
Trunc
,
TruncDate
,
TruncDay
,
ExtractSecond
,
ExtractWeekDay
,
ExtractYear
,
Trunc
,
TruncDate
,
TruncDay
,
TruncHour
,
TruncMinute
,
TruncMonth
,
TruncSecond
,
TruncYear
,
TruncHour
,
TruncMinute
,
TruncMonth
,
TruncSecond
,
Trunc
Time
,
Trunc
Year
,
)
)
from
django.test
import
TestCase
,
override_settings
from
django.test
import
TestCase
,
override_settings
from
django.utils
import
timezone
from
django.utils
import
timezone
...
@@ -512,6 +512,30 @@ class DateFunctionTests(TestCase):
...
@@ -512,6 +512,30 @@ class DateFunctionTests(TestCase):
with
self
.
assertRaisesMessage
(
ValueError
,
"Cannot truncate TimeField 'start_time' to DateField"
):
with
self
.
assertRaisesMessage
(
ValueError
,
"Cannot truncate TimeField 'start_time' to DateField"
):
list
(
DTModel
.
objects
.
annotate
(
truncated
=
TruncDate
(
'start_time'
,
output_field
=
TimeField
())))
list
(
DTModel
.
objects
.
annotate
(
truncated
=
TruncDate
(
'start_time'
,
output_field
=
TimeField
())))
def
test_trunc_time_func
(
self
):
start_datetime
=
microsecond_support
(
datetime
(
2015
,
6
,
15
,
14
,
30
,
50
,
321
))
end_datetime
=
microsecond_support
(
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
=
TruncTime
(
'start_datetime'
))
.
order_by
(
'start_datetime'
),
[
(
start_datetime
,
start_datetime
.
time
()),
(
end_datetime
,
end_datetime
.
time
()),
],
lambda
m
:
(
m
.
start_datetime
,
m
.
extracted
)
)
self
.
assertEqual
(
DTModel
.
objects
.
filter
(
start_datetime__time
=
TruncTime
(
'start_datetime'
))
.
count
(),
2
)
with
self
.
assertRaisesMessage
(
ValueError
,
"Cannot truncate DateField 'start_date' to TimeField"
):
list
(
DTModel
.
objects
.
annotate
(
truncated
=
TruncTime
(
'start_date'
)))
with
self
.
assertRaisesMessage
(
ValueError
,
"Cannot truncate DateField 'start_date' to TimeField"
):
list
(
DTModel
.
objects
.
annotate
(
truncated
=
TruncTime
(
'start_date'
,
output_field
=
DateField
())))
def
test_trunc_day_func
(
self
):
def
test_trunc_day_func
(
self
):
start_datetime
=
microsecond_support
(
datetime
(
2015
,
6
,
15
,
14
,
30
,
50
,
321
))
start_datetime
=
microsecond_support
(
datetime
(
2015
,
6
,
15
,
14
,
30
,
50
,
321
))
end_datetime
=
truncate_to
(
microsecond_support
(
datetime
(
2016
,
6
,
15
,
14
,
10
,
50
,
123
)),
'day'
)
end_datetime
=
truncate_to
(
microsecond_support
(
datetime
(
2016
,
6
,
15
,
14
,
10
,
50
,
123
)),
'day'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment