Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #10164 -- Made AutoField increase monotonically on SQLite

Thanks malte for the report.
  • Loading branch information...
commit eade315da1c8372ac1dfcf1fd20ea87f454d71ac 1 parent 630eb05
@qris qris authored timgraham committed
View
4 django/db/backends/creation.py
@@ -23,6 +23,7 @@ class BaseDatabaseCreation(object):
destruction of test databases.
"""
data_types = {}
+ data_types_suffix = {}
data_type_check_constraints = {}
def __init__(self, connection):
@@ -53,6 +54,7 @@ def sql_create_model(self, model, style, known_models=set()):
qn = self.connection.ops.quote_name
for f in opts.local_fields:
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
if col_type is None:
# Skip ManyToManyFields, because they're not represented as
@@ -88,6 +90,8 @@ def sql_create_model(self, model, style, known_models=set()):
(model, f))
else:
field_output.extend(ref_output)
+ if col_type_suffix:
+ field_output.append(style.SQL_KEYWORD(col_type_suffix))
table_output.append(' '.join(field_output))
for field_constraints in opts.unique_together:
table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' %
View
1  django/db/backends/sqlite3/base.py
@@ -106,6 +106,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_check_constraints = False
autocommits_when_autocommit_is_off = True
supports_paramstyle_pyformat = False
+ supports_sequence_reset = False
@cached_property
def uses_savepoints(self):
View
3  django/db/backends/sqlite3/creation.py
@@ -34,6 +34,9 @@ class DatabaseCreation(BaseDatabaseCreation):
'TextField': 'text',
'TimeField': 'time',
}
+ data_types_suffix = {
+ 'AutoField': 'AUTOINCREMENT',
+ }
def sql_for_pending_references(self, model, style, pending_references):
"SQLite3 doesn't support constraints"
View
2  django/db/backends/sqlite3/introspection.py
@@ -175,7 +175,7 @@ def get_primary_key_column(self, cursor, table_name):
results = results[results.index('(') + 1:results.rindex(')')]
for field_desc in results.split(','):
field_desc = field_desc.strip()
- m = re.search('"(.*)".*PRIMARY KEY$', field_desc)
+ m = re.search('"(.*)".*PRIMARY KEY( AUTOINCREMENT)?$', field_desc)
if m:
return m.groups()[0]
return None
View
3  django/db/models/fields/__init__.py
@@ -395,6 +395,9 @@ def db_parameters(self, connection):
"check": check_string,
}
+ def db_type_suffix(self, connection):
+ return connection.creation.data_types_suffix.get(self.get_internal_type())
+
@property
def unique(self):
return self._unique or self.primary_key
View
8 docs/releases/1.7.txt
@@ -336,6 +336,14 @@ Miscellaneous
when called on an instance without a primary key value. This is done to
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.
@aaugustin Owner

If we want to point to the Trac ticket, we should include an http:// link. But in fact the ticket doesn't provide any migration instructions, so we're really being mean to our users.

I would prefer that we say:

  • this only applies to new databases, not to existing ones;
  • the easiest way to migrate is to dumpdata, rename the database file (keep it as a backup), migrate, loaddata.

It's not hard to explain!

@timgraham Owner

thanks for the poke, updated in 910a576

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
* ``django.contrib.auth.models.AbstractUser`` no longer defines a
:meth:`~django.db.models.Model.get_absolute_url()` method. The old definition
returned ``"/users/%s/" % urlquote(self.username)`` which was arbitrary
View
20 tests/backends/tests.py
@@ -4,6 +4,7 @@
import datetime
from decimal import Decimal
+import re
import threading
import unittest
@@ -108,6 +109,25 @@ def test_order_of_nls_parameters(self):
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):
@unittest.skipUnless(connection.vendor == 'mysql',
"Test valid only for MySQL")
Please sign in to comment.
Something went wrong with that request. Please try again.