diff --git a/django/db/backends/mysql/features.py b/django/db/backends/mysql/features.py index e1d4ce726b..8a2a64c5e4 100644 --- a/django/db/backends/mysql/features.py +++ b/django/db/backends/mysql/features.py @@ -70,6 +70,12 @@ class DatabaseFeatures(BaseDatabaseFeatures): "Confirm support for introspected foreign keys" return self._mysql_storage_engine != 'MyISAM' + @cached_property + def can_return_columns_from_insert(self): + return self.connection.mysql_is_mariadb and self.connection.mysql_version >= (10, 5, 0) + + can_return_rows_from_bulk_insert = property(operator.attrgetter('can_return_columns_from_insert')) + @cached_property def has_zoneinfo_database(self): # Test if the time zone definitions are installed. CONVERT_TZ returns diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py index e9306f03fc..a8e9af2263 100644 --- a/django/db/backends/mysql/operations.py +++ b/django/db/backends/mysql/operations.py @@ -143,6 +143,13 @@ class DatabaseOperations(BaseDatabaseOperations): def date_interval_sql(self, timedelta): return 'INTERVAL %s MICROSECOND' % duration_microseconds(timedelta) + def fetch_returned_insert_rows(self, cursor): + """ + Given a cursor object that has just performed an INSERT...RETURNING + statement into a table, return the tuple of returned data. + """ + return cursor.fetchall() + def format_for_duration_arithmetic(self, sql): return 'INTERVAL %s MICROSECOND' % sql @@ -173,6 +180,19 @@ class DatabaseOperations(BaseDatabaseOperations): def random_function_sql(self): return 'RAND()' + def return_insert_columns(self, fields): + # MySQL and MariaDB < 10.5.0 don'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), () + def sql_flush(self, style, tables, sequences, allow_cascade=False): # NB: The generated SQL below is specific to MySQL # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index 9647b1a8ff..c51c4dd43a 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -2078,9 +2078,9 @@ This has a number of caveats though: * The model's ``save()`` method will not be called, and the ``pre_save`` and ``post_save`` signals will not be sent. * 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` it - does not retrieve and set the primary key attribute, as ``save()`` does, - unless the database backend supports it (currently PostgreSQL). +* 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. * 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 @@ -2110,6 +2110,10 @@ normally supports it). Returns ``objs`` as cast to a list, in the same order as provided. +.. versionchanged:: 3.1 + + Support for the fetching primary key attributes on MariaDB 10.5+ was added. + ``bulk_update()`` ~~~~~~~~~~~~~~~~~ diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt index ecd70feb2e..d133731c25 100644 --- a/docs/releases/3.1.txt +++ b/docs/releases/3.1.txt @@ -344,6 +344,9 @@ Models * The new :class:`~django.db.models.F` expression ``bitxor()`` method allows :ref:`bitwise XOR operation `. +* :meth:`.QuerySet.bulk_create` now sets the primary key on objects when using + MariaDB 10.5+. + Pagination ~~~~~~~~~~