Fixed #10164 -- Made AutoField increase monotonically on SQLite
Thanks malte for the report.
This commit is contained in:
parent
630eb0564a
commit
eade315da1
|
@ -23,6 +23,7 @@ class BaseDatabaseCreation(object):
|
||||||
destruction of test databases.
|
destruction of test databases.
|
||||||
"""
|
"""
|
||||||
data_types = {}
|
data_types = {}
|
||||||
|
data_types_suffix = {}
|
||||||
data_type_check_constraints = {}
|
data_type_check_constraints = {}
|
||||||
|
|
||||||
def __init__(self, connection):
|
def __init__(self, connection):
|
||||||
|
@ -53,6 +54,7 @@ class BaseDatabaseCreation(object):
|
||||||
qn = self.connection.ops.quote_name
|
qn = self.connection.ops.quote_name
|
||||||
for f in opts.local_fields:
|
for f in opts.local_fields:
|
||||||
col_type = f.db_type(connection=self.connection)
|
col_type = f.db_type(connection=self.connection)
|
||||||
|
col_type_suffix = f.db_type_suffix(connection=self.connection)
|
||||||
tablespace = f.db_tablespace or opts.db_tablespace
|
tablespace = f.db_tablespace or opts.db_tablespace
|
||||||
if col_type is None:
|
if col_type is None:
|
||||||
# Skip ManyToManyFields, because they're not represented as
|
# Skip ManyToManyFields, because they're not represented as
|
||||||
|
@ -88,6 +90,8 @@ class BaseDatabaseCreation(object):
|
||||||
(model, f))
|
(model, f))
|
||||||
else:
|
else:
|
||||||
field_output.extend(ref_output)
|
field_output.extend(ref_output)
|
||||||
|
if col_type_suffix:
|
||||||
|
field_output.append(style.SQL_KEYWORD(col_type_suffix))
|
||||||
table_output.append(' '.join(field_output))
|
table_output.append(' '.join(field_output))
|
||||||
for field_constraints in opts.unique_together:
|
for field_constraints in opts.unique_together:
|
||||||
table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' %
|
table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' %
|
||||||
|
|
|
@ -106,6 +106,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
supports_check_constraints = False
|
supports_check_constraints = False
|
||||||
autocommits_when_autocommit_is_off = True
|
autocommits_when_autocommit_is_off = True
|
||||||
supports_paramstyle_pyformat = False
|
supports_paramstyle_pyformat = False
|
||||||
|
supports_sequence_reset = False
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def uses_savepoints(self):
|
def uses_savepoints(self):
|
||||||
|
|
|
@ -34,6 +34,9 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||||
'TextField': 'text',
|
'TextField': 'text',
|
||||||
'TimeField': 'time',
|
'TimeField': 'time',
|
||||||
}
|
}
|
||||||
|
data_types_suffix = {
|
||||||
|
'AutoField': 'AUTOINCREMENT',
|
||||||
|
}
|
||||||
|
|
||||||
def sql_for_pending_references(self, model, style, pending_references):
|
def sql_for_pending_references(self, model, style, pending_references):
|
||||||
"SQLite3 doesn't support constraints"
|
"SQLite3 doesn't support constraints"
|
||||||
|
|
|
@ -175,7 +175,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
results = results[results.index('(') + 1:results.rindex(')')]
|
results = results[results.index('(') + 1:results.rindex(')')]
|
||||||
for field_desc in results.split(','):
|
for field_desc in results.split(','):
|
||||||
field_desc = field_desc.strip()
|
field_desc = field_desc.strip()
|
||||||
m = re.search('"(.*)".*PRIMARY KEY$', field_desc)
|
m = re.search('"(.*)".*PRIMARY KEY( AUTOINCREMENT)?$', field_desc)
|
||||||
if m:
|
if m:
|
||||||
return m.groups()[0]
|
return m.groups()[0]
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -395,6 +395,9 @@ class Field(object):
|
||||||
"check": check_string,
|
"check": check_string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def db_type_suffix(self, connection):
|
||||||
|
return connection.creation.data_types_suffix.get(self.get_internal_type())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique(self):
|
def unique(self):
|
||||||
return self._unique or self.primary_key
|
return self._unique or self.primary_key
|
||||||
|
|
|
@ -336,6 +336,14 @@ Miscellaneous
|
||||||
when called on an instance without a primary key value. This is done to
|
when called on an instance without a primary key value. This is done to
|
||||||
avoid mutable ``__hash__`` values in containers.
|
avoid mutable ``__hash__`` values in containers.
|
||||||
|
|
||||||
|
* The :meth:`django.db.backends.sqlite3.DatabaseCreation.sql_create_model`
|
||||||
|
will now create :class:`~django.db.models.AutoField` columns in SQLite
|
||||||
|
databases using the ``AUTOINCREMENT`` option, which guarantees monotonic
|
||||||
|
increments. This will cause primary key numbering behavior to change on
|
||||||
|
SQLite, becoming consistent with most other SQL databases. If you have a
|
||||||
|
database created with an older version of Django, you will need to migrate
|
||||||
|
it to take advantage of this feature. See ticket #10164 for details.
|
||||||
|
|
||||||
* ``django.contrib.auth.models.AbstractUser`` no longer defines a
|
* ``django.contrib.auth.models.AbstractUser`` no longer defines a
|
||||||
:meth:`~django.db.models.Model.get_absolute_url()` method. The old definition
|
:meth:`~django.db.models.Model.get_absolute_url()` method. The old definition
|
||||||
returned ``"/users/%s/" % urlquote(self.username)`` which was arbitrary
|
returned ``"/users/%s/" % urlquote(self.username)`` which was arbitrary
|
||||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
import re
|
||||||
import threading
|
import threading
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
@ -108,6 +109,25 @@ class OracleChecks(unittest.TestCase):
|
||||||
self.assertEqual(c.fetchone()[0], 1)
|
self.assertEqual(c.fetchone()[0], 1)
|
||||||
|
|
||||||
|
|
||||||
|
class SQLiteTests(TestCase):
|
||||||
|
longMessage = True
|
||||||
|
|
||||||
|
@unittest.skipUnless(connection.vendor == 'sqlite',
|
||||||
|
"Test valid only for SQLite")
|
||||||
|
def test_autoincrement(self):
|
||||||
|
"""
|
||||||
|
Check that auto_increment fields are created with the AUTOINCREMENT
|
||||||
|
keyword in order to be monotonically increasing. Refs #10164.
|
||||||
|
"""
|
||||||
|
statements = connection.creation.sql_create_model(models.Square,
|
||||||
|
style=no_style())
|
||||||
|
match = re.search('"id" ([^,]+),', statements[0][0])
|
||||||
|
self.assertIsNotNone(match)
|
||||||
|
self.assertEqual('integer NOT NULL PRIMARY KEY AUTOINCREMENT',
|
||||||
|
match.group(1), "Wrong SQL used to create an auto-increment "
|
||||||
|
"column on SQLite")
|
||||||
|
|
||||||
|
|
||||||
class MySQLTests(TestCase):
|
class MySQLTests(TestCase):
|
||||||
@unittest.skipUnless(connection.vendor == 'mysql',
|
@unittest.skipUnless(connection.vendor == 'mysql',
|
||||||
"Test valid only for MySQL")
|
"Test valid only for MySQL")
|
||||||
|
|
Loading…
Reference in New Issue