Commit 2dc93bb1 authored by Matthew Somerville's avatar Matthew Somerville Committed by Tim Graham
Browse files

Fixed #22316 -- Added time filters to TimeField on SQLite.

This was implemented for non-SQLite backends in 1.7 (as a
side effect of #16187).
parent 6700c909
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -122,6 +122,13 @@ class BaseDatabaseOperations(object):
        """
        raise NotImplementedError('subclasses of BaseDatabaseOperations may require a datetime_trunk_sql() method')

    def time_extract_sql(self, lookup_type, field_name):
        """
        Given a lookup_type of 'hour', 'minute' or 'second', returns the SQL
        that extracts a value from the given time field field_name.
        """
        return self.date_extract_sql(lookup_type, field_name)

    def deferrable_sql(self):
        """
        Returns the SQL necessary to make a constraint "initially deferred"
+11 −0
Original line number Diff line number Diff line
@@ -210,6 +210,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
        conn.create_function("django_datetime_cast_date", 2, _sqlite_datetime_cast_date)
        conn.create_function("django_datetime_extract", 3, _sqlite_datetime_extract)
        conn.create_function("django_datetime_trunc", 3, _sqlite_datetime_trunc)
        conn.create_function("django_time_extract", 2, _sqlite_time_extract)
        conn.create_function("regexp", 2, _sqlite_regexp)
        conn.create_function("django_format_dtdelta", 3, _sqlite_format_dtdelta)
        conn.create_function("django_power", 2, _sqlite_power)
@@ -402,6 +403,16 @@ def _sqlite_datetime_trunc(lookup_type, dt, tzname):
        return "%i-%02i-%02i %02i:%02i:%02i" % (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)


def _sqlite_time_extract(lookup_type, dt):
    if dt is None:
        return None
    try:
        dt = backend_utils.typecast_time(dt)
    except (ValueError, TypeError):
        return None
    return getattr(dt, lookup_type)


def _sqlite_format_dtdelta(conn, lhs, rhs):
    """
    LHS and RHS can be either:
+7 −0
Original line number Diff line number Diff line
@@ -88,6 +88,13 @@ class DatabaseOperations(BaseDatabaseOperations):
        return "django_datetime_trunc('%s', %s, %%s)" % (
            lookup_type.lower(), field_name), [tzname]

    def time_extract_sql(self, lookup_type, field_name):
        # sqlite doesn't support extract, so we fake it with the user-defined
        # function django_time_extract that's registered in connect(). Note that
        # single quotes are used because this is a string (and could otherwise
        # cause a collision with a field name).
        return "django_time_extract('%s', %s)" % (lookup_type.lower(), field_name)

    def drop_foreignkey_sql(self):
        return ""

+5 −2
Original line number Diff line number Diff line
@@ -2416,9 +2416,12 @@ class DateTransform(Transform):
            tzname = timezone.get_current_timezone_name() if settings.USE_TZ else None
            sql, tz_params = connection.ops.datetime_extract_sql(self.lookup_name, sql, tzname)
            params.extend(tz_params)
        else:
            # DateField and TimeField.
        elif isinstance(lhs_output_field, DateField):
            sql = connection.ops.date_extract_sql(self.lookup_name, sql)
        elif isinstance(lhs_output_field, TimeField):
            sql = connection.ops.time_extract_sql(self.lookup_name, sql)
        else:
            raise ValueError('DateTransform only valid on Date/Time/DateTimeFields')
        return sql, params

    @cached_property
+33 −12
Original line number Diff line number Diff line
@@ -2606,23 +2606,30 @@ in the database <database-time-zone-definitions>`.
hour
~~~~

For datetime fields, an exact hour match. Allows chaining additional field
lookups. Takes an integer between 0 and 23.
For datetime and time fields, an exact hour match. Allows chaining additional
field lookups. Takes an integer between 0 and 23.

Example::

    Event.objects.filter(timestamp__hour=23)
    Event.objects.filter(time__hour=5)
    Event.objects.filter(timestamp__hour__gte=12)

SQL equivalent::

    SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
    SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
    SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';

(The exact SQL syntax varies for each database engine.)

When :setting:`USE_TZ` is ``True``, values are converted to the current time
zone before filtering.
For datetime fields, when :setting:`USE_TZ` is ``True``, values are converted
to the current time zone before filtering.

.. versionchanged:: 1.9

    Added support for :class:`~django.db.models.TimeField` on SQLite (other
    databases supported it as of 1.7).

.. versionchanged:: 1.9

@@ -2633,23 +2640,30 @@ zone before filtering.
minute
~~~~~~

For datetime fields, an exact minute match. Allows chaining additional field
lookups. Takes an integer between 0 and 59.
For datetime and time fields, an exact minute match. Allows chaining additional
field lookups. Takes an integer between 0 and 59.

Example::

    Event.objects.filter(timestamp__minute=29)
    Event.objects.filter(time__minute=46)
    Event.objects.filter(timestamp__minute__gte=29)

SQL equivalent::

    SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
    SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
    SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';

(The exact SQL syntax varies for each database engine.)

When :setting:`USE_TZ` is ``True``, values are converted to the current time
zone before filtering.
For datetime fields, When :setting:`USE_TZ` is ``True``, values are converted
to the current time zone before filtering.

.. versionchanged:: 1.9

    Added support for :class:`~django.db.models.TimeField` on SQLite (other
    databases supported it as of 1.7).

.. versionchanged:: 1.9

@@ -2660,23 +2674,30 @@ zone before filtering.
second
~~~~~~

For datetime fields, an exact second match. Allows chaining additional field
lookups. Takes an integer between 0 and 59.
For datetime and time fields, an exact second match. Allows chaining additional
field lookups. Takes an integer between 0 and 59.

Example::

    Event.objects.filter(timestamp__second=31)
    Event.objects.filter(time__second=2)
    Event.objects.filter(timestamp__second__gte=31)

SQL equivalent::

    SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
    SELECT ... WHERE EXTRACT('second' FROM time) = '2';
    SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';

(The exact SQL syntax varies for each database engine.)

When :setting:`USE_TZ` is ``True``, values are converted to the current time
zone before filtering.
For datetime fields, when :setting:`USE_TZ` is ``True``, values are converted
to the current time zone before filtering.

.. versionchanged:: 1.9

    Added support for :class:`~django.db.models.TimeField` on SQLite (other
    databases supported it as of 1.7).

.. versionchanged:: 1.9

Loading