From a35d2a4510d5beec398b1007aaa26492d6aedf97 Mon Sep 17 00:00:00 2001
From: Nick Pope <nick.pope@flightdataservices.com>
Date: Wed, 12 Sep 2018 23:45:17 +0100
Subject: [PATCH] Refs #23748 -- Added AutoField introspection for SQLite.

---
 django/db/backends/base/features.py         |  4 ++++
 django/db/backends/sqlite3/features.py      |  2 ++
 django/db/backends/sqlite3/introspection.py | 14 +++++++++++++-
 docs/releases/2.2.txt                       |  3 ++-
 tests/introspection/tests.py                |  2 +-
 5 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/django/db/backends/base/features.py b/django/db/backends/base/features.py
index 30d44c4796..8afc7eb516 100644
--- a/django/db/backends/base/features.py
+++ b/django/db/backends/base/features.py
@@ -143,6 +143,10 @@ class BaseDatabaseFeatures:
     # Can the backend introspect a TimeField, instead of a DateTimeField?
     can_introspect_time_field = True
 
+    # Some backends may not be able to differentiate BigAutoField from other
+    # fields such as AutoField.
+    introspected_big_auto_field_type = 'BigAutoField'
+
     # Some backends may not be able to differentiate BooleanField from other
     # fields such as IntegerField.
     introspected_boolean_field_type = 'BooleanField'
diff --git a/django/db/backends/sqlite3/features.py b/django/db/backends/sqlite3/features.py
index 69a42cdc02..19e949899f 100644
--- a/django/db/backends/sqlite3/features.py
+++ b/django/db/backends/sqlite3/features.py
@@ -16,10 +16,12 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     max_query_params = 999
     supports_mixed_date_datetime_comparisons = False
     autocommits_when_autocommit_is_off = sys.version_info < (3, 6)
+    can_introspect_autofield = True
     can_introspect_decimal_field = False
     can_introspect_duration_field = False
     can_introspect_positive_integer_field = True
     can_introspect_small_integer_field = True
+    introspected_big_auto_field_type = 'AutoField'
     supports_transactions = True
     atomic_transactions = False
     can_rollback_ddl = True
diff --git a/django/db/backends/sqlite3/introspection.py b/django/db/backends/sqlite3/introspection.py
index 8ed043ba67..490606c64d 100644
--- a/django/db/backends/sqlite3/introspection.py
+++ b/django/db/backends/sqlite3/introspection.py
@@ -1,12 +1,15 @@
 import re
+from collections import namedtuple
 
 import sqlparse
 
 from django.db.backends.base.introspection import (
-    BaseDatabaseIntrospection, FieldInfo, TableInfo,
+    BaseDatabaseIntrospection, FieldInfo as BaseFieldInfo, TableInfo,
 )
 from django.db.models.indexes import Index
 
+FieldInfo = namedtuple('FieldInfo', BaseFieldInfo._fields + ('pk',))
+
 field_size_re = re.compile(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$')
 
 
@@ -57,6 +60,14 @@ class FlexibleFieldLookupDict:
 class DatabaseIntrospection(BaseDatabaseIntrospection):
     data_types_reverse = FlexibleFieldLookupDict()
 
+    def get_field_type(self, data_type, description):
+        field_type = super().get_field_type(data_type, description)
+        if description.pk and field_type in {'BigIntegerField', 'IntegerField'}:
+            # No support for BigAutoField as SQLite treats all integer primary
+            # keys as signed 64-bit integers.
+            return 'AutoField'
+        return field_type
+
     def get_table_list(self, cursor):
         """Return a list of table and view names in the current database."""
         # Skip the sqlite_sequence system table used for autoincrement key
@@ -82,6 +93,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
                 None,
                 info['null_ok'],
                 info['default'],
+                info['pk'] == 1,
             ) for info in self._table_info(cursor, table_name)
         ]
 
diff --git a/docs/releases/2.2.txt b/docs/releases/2.2.txt
index 65f53c1a49..c8515d5ba6 100644
--- a/docs/releases/2.2.txt
+++ b/docs/releases/2.2.txt
@@ -192,7 +192,8 @@ Management Commands
   created child tables instead the parent.
 
 * :djadmin:`inspectdb` now introspects :class:`~django.db.models.DurationField`
-  for Oracle and PostgreSQL.
+  for Oracle and PostgreSQL, and :class:`~django.db.models.AutoField` for
+  SQLite.
 
 * On Oracle, :djadmin:`dbshell` is wrapped with ``rlwrap``, if available.
   ``rlwrap`` provides a command history and editing of keyboard input.
diff --git a/tests/introspection/tests.py b/tests/introspection/tests.py
index a616ee0f98..4eb868e907 100644
--- a/tests/introspection/tests.py
+++ b/tests/introspection/tests.py
@@ -110,7 +110,7 @@ class IntrospectionTests(TransactionTestCase):
     def test_bigautofield(self):
         with connection.cursor() as cursor:
             desc = connection.introspection.get_table_description(cursor, City._meta.db_table)
-        self.assertIn('BigAutoField', [datatype(r[1], r) for r in desc])
+        self.assertIn(connection.features.introspected_big_auto_field_type, [datatype(r[1], r) for r in desc])
 
     # Regression test for #9991 - 'real' types in postgres
     @skipUnlessDBFeature('has_real_datatype')