1
+ from collections import namedtuple
2
+
1
3
from django .db .backends .base .introspection import (
2
4
BaseDatabaseIntrospection , FieldInfo as BaseFieldInfo , TableInfo ,
3
5
)
6
+ from django .db .models import Index
7
+ from django .utils .datastructures import OrderedSet
4
8
9
+ FieldInfo = namedtuple ('FieldInfo' , BaseFieldInfo ._fields + ('auto_increment' , ))
5
10
6
11
class DatabaseIntrospection (BaseDatabaseIntrospection ):
12
+ data_types_reverse = {
13
+ 'bigint' : 'BigIntegerField' ,
14
+ 'varchar' : 'CharField' ,
15
+ 'integer' : 'IntegerField' ,
16
+ 'bit' : 'BooleanField' ,
17
+ 'date' : 'DateField' ,
18
+ 'timestamp' : 'DateTimeField' ,
19
+ 'numeric' : 'IntegerField' ,
20
+ 'double' : 'FloatField' ,
21
+ 'varbinary' : 'BinaryField' ,
22
+ 'longvarchar' : 'TextField' ,
23
+ 'longvarbinary' : 'BinaryField' ,
24
+ 'time' : 'TimeField' ,
25
+ 'smallint' : 'SmallIntegerField' ,
26
+ 'tinyint' : 'SmallIntegerField' ,
27
+ }
28
+
29
+ def get_field_type (self , data_type , field_info ):
30
+ field_type = super ().get_field_type (data_type , field_info )
31
+ if (field_info .auto_increment and
32
+ field_type in {'BigIntegerField' , 'IntegerField' , 'SmallIntegerField' }):
33
+ return 'AutoField'
34
+ return field_type
35
+
36
+ def get_sequences (self , cursor , table_name , table_fields = ()):
37
+ """
38
+ Return a list of introspected sequences for table_name. Each sequence
39
+ is a dict: {'table': <table_name>, 'column': <column_name>}. An optional
40
+ 'name' key can be added if the backend supports named sequences.
41
+ """
42
+ for field_info in self .get_table_description (cursor , table_name ):
43
+ if 'auto_increment' in field_info and field_info ['auto_increment' ]:
44
+ return [{'table' : table_name , 'column' : field_info .name }]
45
+ return []
7
46
8
47
def get_table_list (self , cursor ):
9
48
cursor .execute ("""
@@ -14,8 +53,109 @@ def get_table_list(self, cursor):
14
53
return [TableInfo (row [0 ], 't' ) for row in cursor .fetchall ()]
15
54
16
55
def get_table_description (self , cursor , table_name ):
17
- print ("get_table_description" , table_name )
18
- return []
56
+ """
57
+ Return a description of the table with the DB-API cursor.description
58
+ interface.
59
+ """
60
+
61
+ cursor .execute ("""
62
+ SELECT
63
+ COLUMN_NAME,
64
+ DATA_TYPE,
65
+ CHARACTER_MAXIMUM_LENGTH,
66
+ NUMERIC_PRECISION,
67
+ NUMERIC_SCALE,
68
+ IS_NULLABLE,
69
+ AUTO_INCREMENT
70
+ FROM INFORMATION_SCHEMA.COLUMNS
71
+ WHERE TABLE_SCHEMA = %s
72
+ AND TABLE_NAME = %s
73
+ ORDER BY ORDINAL_POSITION
74
+ """ ,
75
+ ['SQLUser' , table_name ]
76
+ )
77
+
78
+ description = [
79
+ # name type_code display_size internal_size precision scale null_ok default collation
80
+ # auto_increment
81
+ FieldInfo (
82
+ name ,
83
+ data_type ,
84
+ None ,
85
+ length ,
86
+ precision ,
87
+ scale ,
88
+ isnull == 'YES' ,
89
+ '' ,
90
+ '' ,
91
+ auto_increment == 'YES' ,
92
+ )
93
+ for name , data_type , length , precision , scale , isnull , auto_increment in cursor .fetchall ()
94
+ ]
95
+ return description
19
96
20
97
def get_relations (self , cursor , table_name ):
21
- return []
98
+ """
99
+ Return a dictionary of {field_name: (field_name_other_table, other_table)}
100
+ representing all relationships to the given table.
101
+ """
102
+ # Dictionary of relations to return
103
+ relations = {}
104
+ return relations
105
+
106
+ # def get_primary_key_column(self, cursor, table_name):
107
+ # """
108
+ # Return the name of the primary key column for the given table.
109
+ # """
110
+ # return super().get_primary_key_column(cursor, table_name)
111
+
112
+ def get_constraints (self , cursor , table_name ):
113
+ """
114
+ Retrieve any constraints or keys (unique, pk, fk, check, index)
115
+ across one or more columns.
116
+
117
+ Return a dict mapping constraint names to their attributes,
118
+ where attributes is a dict with keys:
119
+ * columns: List of columns this covers
120
+ * primary_key: True if primary key, False otherwise
121
+ * unique: True if this is a unique constraint, False otherwise
122
+ * foreign_key: (table, column) of target, or None
123
+ * check: True if check constraint, False otherwise
124
+ * index: True if index, False otherwise.
125
+ * orders: The order (ASC/DESC) defined for the columns of indexes
126
+ * type: The type of the index (btree, hash, etc.)
127
+
128
+ Some backends may return special constraint names that don't exist
129
+ if they don't name constraints of a certain type (e.g. SQLite)
130
+ """
131
+ constraints = {}
132
+
133
+ cursor .execute ("""
134
+ SELECT
135
+ INDEX_NAME,
136
+ COLUMN_NAME,
137
+ PRIMARY_KEY,
138
+ NON_UNIQUE,
139
+ ASC_OR_DESC
140
+ FROM INFORMATION_SCHEMA. INDEXES
141
+ WHERE TABLE_SCHEMA = %s
142
+ AND TABLE_NAME = %s
143
+ ORDER BY ORDINAL_POSITION
144
+ """ ,
145
+ ['SQLUser' , table_name ]
146
+ )
147
+ for index , column , primary , non_unique , order in cursor .fetchall ():
148
+ if index not in constraints :
149
+ constraints [index ] = {
150
+ 'columns' : [],
151
+ 'primary_key' : primary == 1 ,
152
+ 'unique' : not non_unique ,
153
+ 'check' : False ,
154
+ 'foreign_key' : None ,
155
+ 'orders' : [],
156
+ }
157
+ constraints [index ]['columns' ].append (column )
158
+ constraints [index ]['orders' ].append (
159
+ 'DESC' if order == 'D' else 'ASC' )
160
+
161
+ return constraints
0 commit comments