Opened 4 years ago
Closed 3 years ago
#32672 closed Cleanup/optimization (fixed)
Primary key constraints aren't detected on SQLite.
Reported by: | jgr88 | Owned by: | Anvesh Mishra |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 3.2 |
Severity: | Normal | Keywords: | SQLite3 PrimaryKey Datatypes |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | yes | UI/UX: | no |
Description (last modified by )
While creating models with "inspectdb" i discovered, that there are currently some issues with SQLite3 Databases.
- PrimaryKeys ain't detected properly
- Datatype double ain't detected properly
- Datatype unsigned int ain't detected properly
Reproduce these issues by creating a SQLite3 Database:
CREATE TABLE "test" ( pId
INTEGER NOT NULL, doubleField
DOUBLE NOT NULL, uInt
UNSIGNED INTEGER NOT NULL, PRIMARY KEY(pId
) )
I added a pullrequest:
https://github.com/django/django/pull/14293
Change History (13)
comment:1 by , 4 years ago
Description: | modified (diff) |
---|---|
Easy pickings: | set |
comment:2 by , 4 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:3 by , 4 years ago
comment:4 by , 4 years ago
Triage Stage: | Unreviewed → Accepted |
---|
OK, this seems a reasonable proposal to me.
Generated model:
class Test(models.Model): pid = models.AutoField(db_column='pId') # Field name made lowercase. doublefield = models.TextField(db_column='doubleField') # Field name made lowercase. This field type is a guess. uint = models.TextField(db_column='uInt') # Field name made lowercase. This field type is a guess. class Meta: managed = False db_table = 'test'
comment:5 by , 4 years ago
I'm fine with fixing detection of primary key, but I think we should not add datatypes that are not used by Django itself. I also don't see a reason to add only DOUBLE
.
SQLite uses complicated rules to determine a datatype affinity based on its name (see Determination Of Column Affinity which have a lot of caveats, e.g.
CHARINT
is mapped toINT
,POINT
is mapped toINT
,STRING
is mapped toNUMERIC
.
I would prefer to warn users about datatypes that are not used by Django instead of mapping some/all of them.
comment:6 by , 4 years ago
Patch needs improvement: | set |
---|
comment:7 by , 4 years ago
Type: | Bug → Cleanup/optimization |
---|
comment:9 by , 3 years ago
So as per Charettes's comment on my PR https://github.com/django/django/pull/14878#discussion_r713268066, I implemented this issue with sqlparse
but failed testcases one of them was inspectdb.tests.InspectDBTestCase.test_attribute_name_not_python_keyword
. The change which I did was
method_match = sqlparse.parse(field_desc)[0] if method_match: if len(method_match.tokens) == 3 and method_match.tokens[0].value == "PRIMARY": column_name_token = str(method_match.tokens[2]) column_name = column_name_token[4:len(column_name_token) - 1] return column_name elif len(method_match.tokens) > 6 and method_match.tokens[6].value == "PRIMARY": return str(method_match.tokens[0])
comment:10 by , 3 years ago
Looks like you forgot to strip leading and trailing quotes, Identifier.get_real_name()
does that
-
django/db/backends/sqlite3/introspection.py
diff --git a/django/db/backends/sqlite3/introspection.py b/django/db/backends/sqlite3/introspection.py index f109b5d5ee..983c000e8b 100644
a b def get_primary_key_column(self, cursor, table_name): 214 214 if table_type == 'view': 215 215 # Views don't have a primary key. 216 216 return None 217 fields_sql = create_sql[create_sql.index('(') + 1:create_sql.rindex(')')] 218 for field_desc in fields_sql.split(','): 219 field_desc = field_desc.strip() 220 m = re.match(r'(?:(?:["`\[])(.*)(?:["`\]])|(\w+)).*PRIMARY KEY.*', field_desc) 221 if m: 222 return m[1] if m[1] else m[2] 217 latest_identifier = None 218 fields = sqlparse.parse(create_sql)[0].tokens[-1] 219 for index, token in enumerate(fields): 220 if isinstance(token, sqlparse.sql.Identifier): 221 latest_identifier = token 222 continue 223 elif (token.match(sqlparse.tokens.Keyword, 'PRIMARY') and 224 fields.token_next(index)[1].match(sqlparse.tokens.Keyword, 'KEY')): 225 return latest_identifier.get_real_name() 223 226 return None 224 227 225 228 def _get_foreign_key_constraints(self, cursor, table_name):
comment:11 by , 3 years ago
Patch needs improvement: | unset |
---|
comment:12 by , 3 years ago
Summary: | Primary Key, type double and type unsigned integer ain't detected correctly for Sqlite3 Database → Primary key constraints aren't detected on SQLite. |
---|---|
Triage Stage: | Accepted → Ready for checkin |
Replying to jgr88:
Update:
I added https://github.com/django/django/pull/14297 since i messed up the first one