Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implemented QuerySet.datetimes on SQLite.

  • Loading branch information...
commit 22d52681d347a8cdf568dc31ed032cbc61d049ef 1 parent f6800fd
@aaugustin aaugustin authored
Showing with 75 additions and 11 deletions.
  1. +75 −11 django/db/backends/sqlite3/base.py
View
86 django/db/backends/sqlite3/base.py
@@ -35,6 +35,10 @@
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured("Error loading either pysqlite2 or sqlite3 modules (tried in that order): %s" % exc)
+try:
+ import pytz
+except ImportError:
+ pytz = None
DatabaseError = Database.DatabaseError
IntegrityError = Database.IntegrityError
@@ -117,6 +121,10 @@ def supports_stddev(self):
cursor.execute('DROP TABLE STDDEV_TEST')
return has_support
+ @cached_property
+ def has_zoneinfo_database(self):
+ return pytz is not None
+
class DatabaseOperations(BaseDatabaseOperations):
def bulk_batch_size(self, fields, objs):
"""
@@ -142,10 +150,10 @@ def check_aggregate_support(self, aggregate):
def date_extract_sql(self, lookup_type, field_name):
# sqlite doesn't support extract, so we fake it with the user-defined
- # function django_extract that's registered in connect(). Note that
+ # function django_date_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_extract('%s', %s)" % (lookup_type.lower(), field_name)
+ return "django_date_extract('%s', %s)" % (lookup_type.lower(), field_name)
def date_interval_sql(self, sql, connector, timedelta):
# It would be more straightforward if we could use the sqlite strftime
@@ -154,7 +162,7 @@ def date_interval_sql(self, sql, connector, timedelta):
# values differently. So instead we register our own function that
# formats the datetime combined with the delta in a manner suitable
# for comparisons.
- return 'django_format_dtdelta(%s, "%s", "%d", "%d", "%d")' % (sql,
+ return 'django_format_dtdelta(%s, "%s", "%d", "%d", "%d")' % (sql,
connector, timedelta.days, timedelta.seconds, timedelta.microseconds)
def date_trunc_sql(self, lookup_type, field_name):
@@ -164,6 +172,32 @@ def date_trunc_sql(self, lookup_type, field_name):
# cause a collision with a field name).
return "django_date_trunc('%s', %s)" % (lookup_type.lower(), field_name)
+ def datetime_extract_sql(self, lookup_type, field_name):
+ # Same comment as in date_extract_sql.
+ if settings.USE_TZ:
+ if pytz is None:
+ from django.core.exceptions import ImproperlyConfigured
+ raise ImproperlyConfigured("This query requires pytz, "
+ "but it isn't installed.")
+ return "django_datetime_extract('%s', %s, %%s)" % (
+ lookup_type.lower(), field_name)
+ else:
+ return "django_datetime_extract('%s', %s, NULL)" % (
+ lookup_type.lower(), field_name)
+
+ def datetime_trunc_sql(self, lookup_type, field_name):
+ # Same comment as in date_trunc_sql.
+ if settings.USE_TZ:
+ if pytz is None:
+ from django.core.exceptions import ImproperlyConfigured
+ raise ImproperlyConfigured("This query requires pytz, "
+ "but it isn't installed.")
+ return "django_datetime_trunc('%s', %s, %%s)" % (
+ lookup_type.lower(), field_name)
+ else:
+ return "django_datetime_trunc('%s', %s, NULL)" % (
+ lookup_type.lower(), field_name)
+
def drop_foreignkey_sql(self):
return ""
@@ -214,11 +248,6 @@ def value_to_db_time(self, value):
return six.text_type(value)
- def year_lookup_bounds(self, value):
- first = '%s-01-01'
- second = '%s-12-31 23:59:59.999999'
- return [first % value, second % value]
-
def convert_values(self, value, field):
"""SQLite returns floats when it should be returning decimals,
and gets dates and datetimes wrong.
@@ -310,9 +339,10 @@ def get_connection_params(self):
def get_new_connection(self, conn_params):
conn = Database.connect(**conn_params)
- # Register extract, date_trunc, and regexp functions.
- conn.create_function("django_extract", 2, _sqlite_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_datetime_extract", 3, _sqlite_datetime_extract)
+ conn.create_function("django_datetime_trunc", 3, _sqlite_datetime_trunc)
conn.create_function("regexp", 2, _sqlite_regexp)
conn.create_function("django_format_dtdelta", 5, _sqlite_format_dtdelta)
return conn
@@ -402,7 +432,7 @@ def executemany(self, query, param_list):
def convert_query(self, query):
return FORMAT_QMARK_REGEX.sub('?', query).replace('%%','%')
-def _sqlite_extract(lookup_type, dt):
+def _sqlite_date_extract(lookup_type, dt):
if dt is None:
return None
try:
@@ -420,11 +450,45 @@ def _sqlite_date_trunc(lookup_type, dt):
except (ValueError, TypeError):
return None
if lookup_type == 'year':
+ return "%i-01-01" % dt.year
+ elif lookup_type == 'month':
+ return "%i-%02i-01" % (dt.year, dt.month)
+ elif lookup_type == 'day':
+ return "%i-%02i-%02i" % (dt.year, dt.month, dt.day)
+
+def _sqlite_datetime_extract(lookup_type, dt, tzname):
+ if dt is None:
+ return None
+ try:
+ dt = util.typecast_timestamp(dt)
+ except (ValueError, TypeError):
+ return None
+ if tzname is not None:
+ dt = timezone.localtime(dt, pytz.timezone(tzname))
+ if lookup_type == 'week_day':
+ return (dt.isoweekday() % 7) + 1
+ else:
+ return getattr(dt, lookup_type)
+
+def _sqlite_datetime_trunc(lookup_type, dt, tzname):
+ try:
+ dt = util.typecast_timestamp(dt)
+ except (ValueError, TypeError):
+ return None
+ if tzname is not None:
+ dt = timezone.localtime(dt, pytz.timezone(tzname))
+ if lookup_type == 'year':
return "%i-01-01 00:00:00" % dt.year
elif lookup_type == 'month':
return "%i-%02i-01 00:00:00" % (dt.year, dt.month)
elif lookup_type == 'day':
return "%i-%02i-%02i 00:00:00" % (dt.year, dt.month, dt.day)
+ elif lookup_type == 'hour':
+ return "%i-%02i-%02i %02i:00:00" % (dt.year, dt.month, dt.day, dt.hour)
+ elif lookup_type == 'minute':
+ return "%i-%02i-%02i %02i:%02i:00" % (dt.year, dt.month, dt.day, dt.hour, dt.minute)
+ elif lookup_type == 'second':
+ return "%i-%02i-%02i %02i:%02i:%02i" % (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
def _sqlite_format_dtdelta(dt, conn, days, secs, usecs):
try:
Please sign in to comment.
Something went wrong with that request. Please try again.