First stab at MySQL support
This commit is contained in:
parent
60873ea2ad
commit
cab044c66c
|
@ -37,6 +37,7 @@ 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
|
||||||
from django.db.backends.mysql.validation import DatabaseValidation
|
from django.db.backends.mysql.validation import DatabaseValidation
|
||||||
|
from django.db.backends.mysql.schema import DatabaseSchemaEditor
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.safestring import SafeString, SafeUnicode
|
from django.utils.safestring import SafeString, SafeUnicode
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
@ -488,3 +489,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
% (table_name, bad_row[0],
|
% (table_name, bad_row[0],
|
||||||
table_name, column_name, bad_row[1],
|
table_name, column_name, bad_row[1],
|
||||||
referenced_table_name, referenced_column_name))
|
referenced_table_name, referenced_column_name))
|
||||||
|
|
||||||
|
def schema_editor(self):
|
||||||
|
"Returns a new instance of this backend's SchemaEditor"
|
||||||
|
return DatabaseSchemaEditor(self)
|
||||||
|
|
|
@ -102,3 +102,35 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
indexes[row[4]] = {'primary_key': (row[2] == 'PRIMARY'), 'unique': not bool(row[1])}
|
indexes[row[4]] = {'primary_key': (row[2] == 'PRIMARY'), 'unique': not bool(row[1])}
|
||||||
return indexes
|
return indexes
|
||||||
|
|
||||||
|
def get_constraints(self, cursor, table_name):
|
||||||
|
"""
|
||||||
|
Retrieves any constraints (unique, pk, fk, check) across one or more columns.
|
||||||
|
Returns {'cnname': {'columns': set(columns), 'primary_key': bool, 'unique': bool}}
|
||||||
|
"""
|
||||||
|
constraints = {}
|
||||||
|
# Loop over the constraint tables, collecting things as constraints
|
||||||
|
ifsc_tables = ["constraint_column_usage", "key_column_usage"]
|
||||||
|
for ifsc_table in ifsc_tables:
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT kc.constraint_name, kc.column_name, c.constraint_type
|
||||||
|
FROM information_schema.%s AS kc
|
||||||
|
JOIN information_schema.table_constraints AS c ON
|
||||||
|
kc.table_schema = c.table_schema AND
|
||||||
|
kc.table_name = c.table_name AND
|
||||||
|
kc.constraint_name = c.constraint_name
|
||||||
|
WHERE
|
||||||
|
kc.table_schema = %%s AND
|
||||||
|
kc.table_name = %%s
|
||||||
|
""" % ifsc_table, [self.connection.settings_dict['NAME'], table_name])
|
||||||
|
for constraint, column, kind in cursor.fetchall():
|
||||||
|
# If we're the first column, make the record
|
||||||
|
if constraint not in constraints:
|
||||||
|
constraints[constraint] = {
|
||||||
|
"columns": set(),
|
||||||
|
"primary_key": kind.lower() == "primary key",
|
||||||
|
"foreign_key": kind.lower() == "foreign key",
|
||||||
|
"unique": kind.lower() in ["primary key", "unique"],
|
||||||
|
}
|
||||||
|
# Record the details
|
||||||
|
constraints[constraint]['columns'].add(column)
|
||||||
|
return constraints
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
from django.db.backends.schema import BaseDatabaseSchemaEditor
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
||||||
|
|
||||||
|
sql_rename_table = "RENAME TABLE %(old_table)s TO %(new_table)s"
|
||||||
|
|
||||||
|
sql_alter_column_null = "MODIFY %(column)s %(type)s NULL"
|
||||||
|
sql_alter_column_not_null = "MODIFY %(column)s %(type)s NULL"
|
||||||
|
|
||||||
|
sql_delete_unique = "ALTER TABLE %(table)s DROP INDEX %(name)s"
|
||||||
|
|
||||||
|
sql_create_fk = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s FOREIGN KEY (%(column)s) REFERENCES %(to_table)s (%(to_column)s)"
|
||||||
|
sql_delete_fk = "ALTER TABLE %(table)s DROP FOREIGN KEY %(name)s"
|
||||||
|
|
||||||
|
sql_delete_index = "DROP INDEX %(name)s ON %(table_name)s"
|
||||||
|
|
||||||
|
sql_delete_pk = "ALTER TABLE %(table)s DROP PRIMARY KEY"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
alter_string_set_null = 'MODIFY %(column)s %(type)s NULL;'
|
||||||
|
alter_string_drop_null = 'MODIFY %(column)s %(type)s NOT NULL;'
|
|
@ -91,7 +91,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
|
|
||||||
def get_constraints(self, cursor, table_name):
|
def get_constraints(self, cursor, table_name):
|
||||||
"""
|
"""
|
||||||
Retrieves any constraints (unique, pk, check) across one or more columns.
|
Retrieves any constraints (unique, pk, fk, check) across one or more columns.
|
||||||
Returns {'cnname': {'columns': set(columns), 'primary_key': bool, 'unique': bool}}
|
Returns {'cnname': {'columns': set(columns), 'primary_key': bool, 'unique': bool}}
|
||||||
"""
|
"""
|
||||||
constraints = {}
|
constraints = {}
|
||||||
|
|
|
@ -167,7 +167,6 @@ class SchemaTests(TestCase):
|
||||||
# Ensure the field is right to begin with
|
# Ensure the field is right to begin with
|
||||||
columns = self.column_classes(Author)
|
columns = self.column_classes(Author)
|
||||||
self.assertEqual(columns['name'][0], "CharField")
|
self.assertEqual(columns['name'][0], "CharField")
|
||||||
self.assertEqual(columns['name'][1][3], 255)
|
|
||||||
self.assertEqual(columns['name'][1][6], False)
|
self.assertEqual(columns['name'][1][6], False)
|
||||||
# Alter the name field to a TextField
|
# Alter the name field to a TextField
|
||||||
new_field = TextField(null=True)
|
new_field = TextField(null=True)
|
||||||
|
@ -197,7 +196,6 @@ class SchemaTests(TestCase):
|
||||||
# Ensure the field is right to begin with
|
# Ensure the field is right to begin with
|
||||||
columns = self.column_classes(Author)
|
columns = self.column_classes(Author)
|
||||||
self.assertEqual(columns['name'][0], "CharField")
|
self.assertEqual(columns['name'][0], "CharField")
|
||||||
self.assertEqual(columns['name'][1][3], 255)
|
|
||||||
self.assertNotIn("display_name", columns)
|
self.assertNotIn("display_name", columns)
|
||||||
# Alter the name field's name
|
# Alter the name field's name
|
||||||
new_field = CharField(max_length=254)
|
new_field = CharField(max_length=254)
|
||||||
|
@ -213,7 +211,6 @@ class SchemaTests(TestCase):
|
||||||
# Ensure the field is right afterwards
|
# Ensure the field is right afterwards
|
||||||
columns = self.column_classes(Author)
|
columns = self.column_classes(Author)
|
||||||
self.assertEqual(columns['display_name'][0], "CharField")
|
self.assertEqual(columns['display_name'][0], "CharField")
|
||||||
self.assertEqual(columns['display_name'][1][3], 254)
|
|
||||||
self.assertNotIn("name", columns)
|
self.assertNotIn("name", columns)
|
||||||
|
|
||||||
def test_m2m(self):
|
def test_m2m(self):
|
||||||
|
|
Loading…
Reference in New Issue