diff --git a/dts_test_project/dts_test_app/migrations/0003_test_add_db_index.py b/dts_test_project/dts_test_app/migrations/0003_test_add_db_index.py new file mode 100644 index 0000000..4f3f6fb --- /dev/null +++ b/dts_test_project/dts_test_app/migrations/0003_test_add_db_index.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + ('dts_test_app', '0002_test_drop_unique'), + ] + + operations = [ + migrations.AddField( + model_name='DummyModel', + name='indexed_value', + field=models.CharField(max_length=255, db_index=True), + ), + ] diff --git a/dts_test_project/dts_test_app/migrations/0004_test_alter_unique.py b/dts_test_project/dts_test_app/migrations/0004_test_alter_unique.py new file mode 100644 index 0000000..5f1828a --- /dev/null +++ b/dts_test_project/dts_test_app/migrations/0004_test_alter_unique.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + ('dts_test_app', '0003_test_add_db_index'), + ] + + operations = [ + migrations.AlterField( + model_name='DummyModel', + name='indexed_value', + field=models.CharField(max_length=255, unique=True), + ), + + migrations.RemoveField( + model_name='DummyModel', + name='indexed_value', + ), + ] diff --git a/tenant_schemas/postgresql_backend/introspection.py b/tenant_schemas/postgresql_backend/introspection.py index ca445d4..7ff2cca 100644 --- a/tenant_schemas/postgresql_backend/introspection.py +++ b/tenant_schemas/postgresql_backend/introspection.py @@ -5,6 +5,11 @@ from collections import namedtuple from django.db.backends.base.introspection import ( BaseDatabaseIntrospection, FieldInfo, TableInfo, ) +try: + # Django >= 1.11 + from django.db.models.indexes import Index +except ImportError: + Index = None from django.utils.encoding import force_text fields = FieldInfo._fields @@ -113,7 +118,8 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection): FROM pg_attribute AS fka JOIN pg_class AS fkc ON fka.attrelid = fkc.oid WHERE fka.attrelid = c.confrelid - AND fka.attnum = c.confkey[1]) + AND fka.attnum = c.confkey[1]), + cl.reloptions FROM pg_constraint AS c JOIN pg_class AS cl ON c.conrelid = cl.oid JOIN pg_namespace AS ns ON cl.relnamespace = ns.oid @@ -135,35 +141,37 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection): _get_index_constraints_query = """ SELECT - indexname, array_agg(attname), indisunique, indisprimary, - array_agg(ordering), amname, exprdef + indexname, array_agg(attname ORDER BY rnum), indisunique, indisprimary, + array_agg(ordering ORDER BY rnum), amname, exprdef, s2.attoptions + FROM ( + SELECT + row_number() OVER () as rnum, c2.relname as indexname, + idx.*, attr.attname, am.amname, + CASE + WHEN idx.indexprs IS NOT NULL THEN + pg_get_indexdef(idx.indexrelid) + END AS exprdef, + CASE am.amname + WHEN 'btree' THEN + CASE (option & 1) + WHEN 1 THEN 'DESC' ELSE 'ASC' + END + END as ordering, + c2.reloptions as attoptions FROM ( SELECT - c2.relname as indexname, idx.*, attr.attname, am.amname, - CASE - WHEN idx.indexprs IS NOT NULL THEN - pg_get_indexdef(idx.indexrelid) - END AS exprdef, - CASE am.amname - WHEN 'btree' THEN - CASE (option & 1) - WHEN 1 THEN 'DESC' ELSE 'ASC' - END - END as ordering - FROM ( - SELECT - *, unnest(i.indkey) as key, unnest(i.indoption) as option - FROM pg_index i - ) idx - LEFT JOIN pg_class c ON idx.indrelid = c.oid - LEFT JOIN pg_class c2 ON idx.indexrelid = c2.oid - LEFT JOIN pg_am am ON c2.relam = am.oid - LEFT JOIN pg_attribute attr ON attr.attrelid = c.oid AND attr.attnum = idx.key - LEFT JOIN pg_namespace n ON c.relnamespace = n.oid - WHERE c.relname = %(table)s - AND n.nspname = %(schema)s - ) s2 - GROUP BY indexname, indisunique, indisprimary, amname, exprdef; + *, unnest(i.indkey) as key, unnest(i.indoption) as option + FROM pg_index i + ) idx + LEFT JOIN pg_class c ON idx.indrelid = c.oid + LEFT JOIN pg_class c2 ON idx.indexrelid = c2.oid + LEFT JOIN pg_am am ON c2.relam = am.oid + LEFT JOIN pg_attribute attr ON attr.attrelid = c.oid AND attr.attnum = idx.key + LEFT JOIN pg_namespace n ON c.relnamespace = n.oid + WHERE c.relname = %(table)s + AND n.nspname = %(schema)s + ) s2 + GROUP BY indexname, indisunique, indisprimary, amname, exprdef, attoptions; """ def get_field_type(self, data_type, description): @@ -274,7 +282,7 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection): 'table': table_name, }) - for constraint, columns, kind, used_cols in cursor.fetchall(): + for constraint, columns, kind, used_cols, options in cursor.fetchall(): constraints[constraint] = { "columns": columns, "primary_key": kind == "p", @@ -283,6 +291,7 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection): "check": kind == "c", "index": False, "definition": None, + "options": options, } # Now get indexes @@ -291,7 +300,7 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection): 'table': table_name, }) - for index, columns, unique, primary, orders, type_, definition in cursor.fetchall(): + for index, columns, unique, primary, orders, type_, definition, options in cursor.fetchall(): if index not in constraints: constraints[index] = { "columns": columns if columns != [None] else [], @@ -301,7 +310,8 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection): "foreign_key": None, "check": False, "index": True, - "type": type_, + "type": Index.suffix if type_ == 'btree' and Index else type_, "definition": definition, + "options": options, } return constraints