Browse Source

Fixed #31403 -- Added support for returning fields from INSERT statements on MariaDB 10.5+.

Adam Johnson 5 years ago
parent
commit
93ed71e058

+ 6 - 0
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

+ 20 - 0
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

+ 7 - 3
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()``
 ~~~~~~~~~~~~~~~~~
 

+ 3 - 0
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 <using-f-expressions-in-filters>`.
 
+* :meth:`.QuerySet.bulk_create` now sets the primary key on objects when using
+  MariaDB 10.5+.
+
 Pagination
 ~~~~~~~~~~