diff --git a/django/db/backends/sqlite3/features.py b/django/db/backends/sqlite3/features.py index ddae4c8efa..6a7aa09fc9 100644 --- a/django/db/backends/sqlite3/features.py +++ b/django/db/backends/sqlite3/features.py @@ -117,3 +117,9 @@ class DatabaseFeatures(BaseDatabaseFeatures): can_introspect_json_field = property(operator.attrgetter('supports_json_field')) has_json_object_function = property(operator.attrgetter('supports_json_field')) + + @cached_property + def can_return_columns_from_insert(self): + return Database.sqlite_version_info >= (3, 35) + + can_return_rows_from_bulk_insert = property(operator.attrgetter('can_return_columns_from_insert')) diff --git a/django/db/backends/sqlite3/operations.py b/django/db/backends/sqlite3/operations.py index c578979777..95484931cf 100644 --- a/django/db/backends/sqlite3/operations.py +++ b/django/db/backends/sqlite3/operations.py @@ -76,6 +76,13 @@ class DatabaseOperations(BaseDatabaseOperations): """ return "django_date_extract('%s', %s)" % (lookup_type.lower(), field_name) + def fetch_returned_insert_rows(self, cursor): + """ + Given a cursor object that has just performed an INSERT...RETURNING + statement into a table, return the list of returned data. + """ + return cursor.fetchall() + def format_for_duration_arithmetic(self, sql): """Do nothing since formatting is handled in the custom function.""" return sql @@ -365,3 +372,15 @@ class DatabaseOperations(BaseDatabaseOperations): def insert_statement(self, ignore_conflicts=False): return 'INSERT OR IGNORE INTO' if ignore_conflicts else super().insert_statement(ignore_conflicts) + + def return_insert_columns(self, fields): + # SQLite < 3.35 doesn't support an INSERT...RETURNING statement. + if not fields: + return '', () + columns = [ + '%s.%s' % ( + self.quote_name(field.model._meta.db_table), + self.quote_name(field.column), + ) for field in fields + ] + return 'RETURNING %s' % ', '.join(columns), () diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index e874211a54..dbca894715 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -2171,7 +2171,8 @@ This has a number of caveats though: * It does not work with child models in a multi-table inheritance scenario. * If the model's primary key is an :class:`~django.db.models.AutoField`, the primary key attribute can only be retrieved on certain databases (currently - PostgreSQL and MariaDB 10.5+). On other databases, it will not be set. + PostgreSQL, MariaDB 10.5+, and SQLite 3.35+). On other databases, it will not + be set. * It does not work with many-to-many relationships. * It casts ``objs`` to a list, which fully evaluates ``objs`` if it's a generator. The cast allows inspecting all objects so that any objects with a @@ -2210,6 +2211,10 @@ normally supports it). .. _MySQL documentation: https://dev.mysql.com/doc/refman/en/sql-mode.html#ignore-strict-comparison .. _MariaDB documentation: https://mariadb.com/kb/en/ignore/ +.. versionchanged:: 4.0 + + Support for the fetching primary key attributes on SQLite 3.35+ was added. + ``bulk_update()`` ~~~~~~~~~~~~~~~~~ diff --git a/docs/releases/4.0.txt b/docs/releases/4.0.txt index 656cf23fa8..a3429b6baf 100644 --- a/docs/releases/4.0.txt +++ b/docs/releases/4.0.txt @@ -230,6 +230,9 @@ Models :class:`Round() ` database function allows specifying the number of decimal places after rounding. +* :meth:`.QuerySet.bulk_create` now sets the primary key on objects when using + SQLite 3.35+. + Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~