Merge pull request #1 from alexanderdidenko/patch-1
Update DatabaseWrapper class to operate similarly to the standard MySQL backend
This commit is contained in:
commit
8d02315985
|
@ -22,7 +22,6 @@ import mysql.connector.conversion
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django.db.backends import *
|
from django.db.backends import *
|
||||||
from django.db.backends.mysql import base as mysqldb_base
|
|
||||||
from django.db.backends.mysql.client import DatabaseClient
|
from django.db.backends.mysql.client import DatabaseClient
|
||||||
from django.db.backends.mysql.creation import DatabaseCreation
|
from django.db.backends.mysql.creation import DatabaseCreation
|
||||||
from django.db.backends.mysql.introspection import DatabaseIntrospection
|
from django.db.backends.mysql.introspection import DatabaseIntrospection
|
||||||
|
@ -31,12 +30,9 @@ from django.utils.safestring import SafeString, SafeUnicode
|
||||||
|
|
||||||
# Raise exceptions for database warnings if DEBUG is on
|
# Raise exceptions for database warnings if DEBUG is on
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
#if settings.DEBUG:
|
||||||
# NOTE: Disabling this since `mysql.connector.Database.Warning` is a
|
# from warnings import filterwarnings
|
||||||
# subclass of StandardError instead of a "warning"
|
# filterwarnings("error", category=Database.Warning)
|
||||||
if False: #settings.DEBUG:
|
|
||||||
from warnings import filterwarnings
|
|
||||||
filterwarnings("error", category=Database.Warning)
|
|
||||||
|
|
||||||
DatabaseError = Database.DatabaseError
|
DatabaseError = Database.DatabaseError
|
||||||
IntegrityError = Database.IntegrityError
|
IntegrityError = Database.IntegrityError
|
||||||
|
@ -47,7 +43,7 @@ class DjangoMySQLConverter(Database.conversion.MySQLConverter):
|
||||||
"""
|
"""
|
||||||
def _TIME_to_python(self, v, dsc=None):
|
def _TIME_to_python(self, v, dsc=None):
|
||||||
return util.typecast_time(v)
|
return util.typecast_time(v)
|
||||||
|
|
||||||
def _decimal(self, v, desc=None):
|
def _decimal(self, v, desc=None):
|
||||||
return util.typecast_decimal(v)
|
return util.typecast_decimal(v)
|
||||||
"""
|
"""
|
||||||
|
@ -65,11 +61,98 @@ server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})')
|
||||||
# TRADITIONAL will automatically cause most warnings to be treated as errors.
|
# TRADITIONAL will automatically cause most warnings to be treated as errors.
|
||||||
|
|
||||||
class DatabaseFeatures(BaseDatabaseFeatures):
|
class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
allows_group_by_pk = True
|
|
||||||
autoindexes_primary_keys = False
|
autoindexes_primary_keys = False
|
||||||
inline_fk_references = False
|
inline_fk_references = False
|
||||||
related_fields_match_type = True
|
|
||||||
update_can_self_select = False
|
class DatabaseOperations(BaseDatabaseOperations):
|
||||||
|
def date_extract_sql(self, lookup_type, field_name):
|
||||||
|
# http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
|
||||||
|
return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name)
|
||||||
|
|
||||||
|
def date_trunc_sql(self, lookup_type, field_name):
|
||||||
|
fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
|
||||||
|
format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape.
|
||||||
|
format_def = ('0000-', '01', '-01', ' 00:', '00', ':00')
|
||||||
|
try:
|
||||||
|
i = fields.index(lookup_type) + 1
|
||||||
|
except ValueError:
|
||||||
|
sql = field_name
|
||||||
|
else:
|
||||||
|
format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]])
|
||||||
|
sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
|
||||||
|
return sql
|
||||||
|
|
||||||
|
def drop_foreignkey_sql(self):
|
||||||
|
return "DROP FOREIGN KEY"
|
||||||
|
|
||||||
|
def fulltext_search_sql(self, field_name):
|
||||||
|
return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
|
||||||
|
|
||||||
|
def limit_offset_sql(self, limit, offset=None):
|
||||||
|
# 'LIMIT 20,40'
|
||||||
|
sql = "LIMIT "
|
||||||
|
if offset and offset != 0:
|
||||||
|
sql += "%s," % offset
|
||||||
|
return sql + str(limit)
|
||||||
|
|
||||||
|
def quote_name(self, name):
|
||||||
|
if name.startswith("`") and name.endswith("`"):
|
||||||
|
return name # Quoting once is enough.
|
||||||
|
return "`%s`" % name
|
||||||
|
|
||||||
|
def random_function_sql(self):
|
||||||
|
return 'RAND()'
|
||||||
|
|
||||||
|
def sql_flush(self, style, tables, sequences):
|
||||||
|
# NB: The generated SQL below is specific to MySQL
|
||||||
|
# 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
|
||||||
|
# to clear all tables of all data
|
||||||
|
if tables:
|
||||||
|
sql = ['SET FOREIGN_KEY_CHECKS = 0;']
|
||||||
|
for table in tables:
|
||||||
|
sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.quote_name(table))))
|
||||||
|
sql.append('SET FOREIGN_KEY_CHECKS = 1;')
|
||||||
|
|
||||||
|
# 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
|
||||||
|
# to reset sequence indices
|
||||||
|
sql.extend(["%s %s %s %s %s;" % \
|
||||||
|
(style.SQL_KEYWORD('ALTER'),
|
||||||
|
style.SQL_KEYWORD('TABLE'),
|
||||||
|
style.SQL_TABLE(self.quote_name(sequence['table'])),
|
||||||
|
style.SQL_KEYWORD('AUTO_INCREMENT'),
|
||||||
|
style.SQL_FIELD('= 1'),
|
||||||
|
) for sequence in sequences])
|
||||||
|
return sql
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def value_to_db_datetime(self, value):
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# MySQL doesn't support tz-aware datetimes
|
||||||
|
if value.tzinfo is not None:
|
||||||
|
raise ValueError("MySQL backend does not support timezone-aware datetimes.")
|
||||||
|
|
||||||
|
# MySQL doesn't support microseconds
|
||||||
|
return unicode(value.replace(microsecond=0))
|
||||||
|
|
||||||
|
def value_to_db_time(self, value):
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# MySQL doesn't support tz-aware datetimes
|
||||||
|
if value.tzinfo is not None:
|
||||||
|
raise ValueError("MySQL backend does not support timezone-aware datetimes.")
|
||||||
|
|
||||||
|
# MySQL doesn't support microseconds
|
||||||
|
return unicode(value.replace(microsecond=0))
|
||||||
|
|
||||||
|
def year_lookup_bounds(self, value):
|
||||||
|
# Again, no microseconds
|
||||||
|
first = '%s-01-01 00:00:00'
|
||||||
|
second = '%s-12-31 23:59:59.99'
|
||||||
|
return [first % value, second % value]
|
||||||
|
|
||||||
|
|
||||||
class DatabaseWrapper(BaseDatabaseWrapper):
|
class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
|
@ -93,14 +176,14 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(DatabaseWrapper, self).__init__(*args, **kwargs)
|
super(DatabaseWrapper, self).__init__(*args, **kwargs)
|
||||||
self.server_version = None
|
|
||||||
|
|
||||||
self.features = DatabaseFeatures()
|
self.server_version = None
|
||||||
self.ops = mysqldb_base.DatabaseOperations()
|
self.features = DatabaseFeatures(self)
|
||||||
|
self.ops = DatabaseOperations()
|
||||||
self.client = DatabaseClient(self)
|
self.client = DatabaseClient(self)
|
||||||
self.creation = DatabaseCreation(self)
|
self.creation = DatabaseCreation(self)
|
||||||
self.introspection = DatabaseIntrospection(self)
|
self.introspection = DatabaseIntrospection(self)
|
||||||
self.validation = DatabaseValidation()
|
self.validation = DatabaseValidation(self)
|
||||||
|
|
||||||
def _valid_connection(self):
|
def _valid_connection(self):
|
||||||
if self.connection is not None:
|
if self.connection is not None:
|
||||||
|
@ -120,19 +203,19 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
'use_unicode': True,
|
'use_unicode': True,
|
||||||
}
|
}
|
||||||
settings_dict = self.settings_dict
|
settings_dict = self.settings_dict
|
||||||
if settings_dict['DATABASE_USER']:
|
if settings_dict['USER']:
|
||||||
kwargs['user'] = settings_dict['DATABASE_USER']
|
kwargs['user'] = settings_dict['USER']
|
||||||
if settings_dict['DATABASE_NAME']:
|
if settings_dict['NAME']:
|
||||||
kwargs['db'] = settings_dict['DATABASE_NAME']
|
kwargs['db'] = settings_dict['NAME']
|
||||||
if settings_dict['DATABASE_PASSWORD']:
|
if settings_dict['PASSWORD']:
|
||||||
kwargs['password'] = settings_dict['DATABASE_PASSWORD']
|
kwargs['passwd'] = settings_dict['PASSWORD']
|
||||||
if settings_dict['DATABASE_HOST'].startswith('/'):
|
if settings_dict['HOST'].startswith('/'):
|
||||||
kwargs['unix_socket'] = settings_dict['DATABASE_HOST']
|
kwargs['unix_socket'] = settings_dict['HOST']
|
||||||
elif settings_dict['DATABASE_HOST']:
|
elif settings_dict['HOST']:
|
||||||
kwargs['host'] = settings_dict['DATABASE_HOST']
|
kwargs['host'] = settings_dict['HOST']
|
||||||
if settings_dict['DATABASE_PORT']:
|
if settings_dict['PORT']:
|
||||||
kwargs['port'] = int(settings_dict['DATABASE_PORT'])
|
kwargs['port'] = int(settings_dict['PORT'])
|
||||||
kwargs.update(settings_dict['DATABASE_OPTIONS'])
|
kwargs.update(settings_dict['OPTIONS'])
|
||||||
self.connection = Database.connect(**kwargs)
|
self.connection = Database.connect(**kwargs)
|
||||||
self.connection.set_converter_class(DjangoMySQLConverter)
|
self.connection.set_converter_class(DjangoMySQLConverter)
|
||||||
cursor = self.connection.cursor()
|
cursor = self.connection.cursor()
|
||||||
|
|
Loading…
Reference in New Issue