backported django postgres backend fixes

This commit is contained in:
Guillaume Andreu Sabater 2017-12-06 16:30:14 +01:00
parent 20c72782ce
commit 7239b91a47
3 changed files with 86 additions and 31 deletions

View File

@ -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),
),
]

View File

@ -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',
),
]

View File

@ -5,6 +5,11 @@ from collections import namedtuple
from django.db.backends.base.introspection import ( from django.db.backends.base.introspection import (
BaseDatabaseIntrospection, FieldInfo, TableInfo, 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 from django.utils.encoding import force_text
fields = FieldInfo._fields fields = FieldInfo._fields
@ -113,7 +118,8 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection):
FROM pg_attribute AS fka FROM pg_attribute AS fka
JOIN pg_class AS fkc ON fka.attrelid = fkc.oid JOIN pg_class AS fkc ON fka.attrelid = fkc.oid
WHERE fka.attrelid = c.confrelid WHERE fka.attrelid = c.confrelid
AND fka.attnum = c.confkey[1]) AND fka.attnum = c.confkey[1]),
cl.reloptions
FROM pg_constraint AS c FROM pg_constraint AS c
JOIN pg_class AS cl ON c.conrelid = cl.oid JOIN pg_class AS cl ON c.conrelid = cl.oid
JOIN pg_namespace AS ns ON cl.relnamespace = ns.oid JOIN pg_namespace AS ns ON cl.relnamespace = ns.oid
@ -135,35 +141,37 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection):
_get_index_constraints_query = """ _get_index_constraints_query = """
SELECT SELECT
indexname, array_agg(attname), indisunique, indisprimary, indexname, array_agg(attname ORDER BY rnum), indisunique, indisprimary,
array_agg(ordering), amname, exprdef 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 ( FROM (
SELECT SELECT
c2.relname as indexname, idx.*, attr.attname, am.amname, *, unnest(i.indkey) as key, unnest(i.indoption) as option
CASE FROM pg_index i
WHEN idx.indexprs IS NOT NULL THEN ) idx
pg_get_indexdef(idx.indexrelid) LEFT JOIN pg_class c ON idx.indrelid = c.oid
END AS exprdef, LEFT JOIN pg_class c2 ON idx.indexrelid = c2.oid
CASE am.amname LEFT JOIN pg_am am ON c2.relam = am.oid
WHEN 'btree' THEN LEFT JOIN pg_attribute attr ON attr.attrelid = c.oid AND attr.attnum = idx.key
CASE (option & 1) LEFT JOIN pg_namespace n ON c.relnamespace = n.oid
WHEN 1 THEN 'DESC' ELSE 'ASC' WHERE c.relname = %(table)s
END AND n.nspname = %(schema)s
END as ordering ) s2
FROM ( GROUP BY indexname, indisunique, indisprimary, amname, exprdef, attoptions;
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;
""" """
def get_field_type(self, data_type, description): def get_field_type(self, data_type, description):
@ -274,7 +282,7 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection):
'table': table_name, 'table': table_name,
}) })
for constraint, columns, kind, used_cols in cursor.fetchall(): for constraint, columns, kind, used_cols, options in cursor.fetchall():
constraints[constraint] = { constraints[constraint] = {
"columns": columns, "columns": columns,
"primary_key": kind == "p", "primary_key": kind == "p",
@ -283,6 +291,7 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection):
"check": kind == "c", "check": kind == "c",
"index": False, "index": False,
"definition": None, "definition": None,
"options": options,
} }
# Now get indexes # Now get indexes
@ -291,7 +300,7 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection):
'table': table_name, '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: if index not in constraints:
constraints[index] = { constraints[index] = {
"columns": columns if columns != [None] else [], "columns": columns if columns != [None] else [],
@ -301,7 +310,8 @@ class DatabaseSchemaIntrospection(BaseDatabaseIntrospection):
"foreign_key": None, "foreign_key": None,
"check": False, "check": False,
"index": True, "index": True,
"type": type_, "type": Index.suffix if type_ == 'btree' and Index else type_,
"definition": definition, "definition": definition,
"options": options,
} }
return constraints return constraints