diff options
author | sean_c_hsu <s8901489@gmail.com> | 2020-06-15 00:58:06 +0800 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-01-19 20:17:42 +0100 |
commit | 0f6946495a8ec955b471ca1baaf408ceb53d4796 (patch) | |
tree | c3d867d141074fb990d3140e02fbaa9d717e8ff2 /django/db/backends/mysql/operations.py | |
parent | ba9de2e74edb155067dc96a3369305c9ef4ba385 (diff) | |
download | django-0f6946495a8ec955b471ca1baaf408ceb53d4796.tar.gz |
Fixed #31685 -- Added support for updating conflicts to QuerySet.bulk_create().
Thanks Florian Apolloner, Chris Jerdonek, Hannes Ljungberg, Nick Pope,
and Mariusz Felisiak for reviews.
Diffstat (limited to 'django/db/backends/mysql/operations.py')
-rw-r--r-- | django/db/backends/mysql/operations.py | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py index c878664a5c..923e50a8d4 100644 --- a/django/db/backends/mysql/operations.py +++ b/django/db/backends/mysql/operations.py @@ -4,6 +4,7 @@ from django.conf import settings from django.db.backends.base.operations import BaseDatabaseOperations from django.db.backends.utils import split_tzname_delta from django.db.models import Exists, ExpressionWrapper, Lookup +from django.db.models.constants import OnConflict from django.utils import timezone from django.utils.encoding import force_str @@ -365,8 +366,10 @@ class DatabaseOperations(BaseDatabaseOperations): match_option = 'c' if lookup_type == 'regex' else 'i' return "REGEXP_LIKE(%%s, %%s, '%s')" % match_option - def insert_statement(self, ignore_conflicts=False): - return 'INSERT IGNORE INTO' if ignore_conflicts else super().insert_statement(ignore_conflicts) + def insert_statement(self, on_conflict=None): + if on_conflict == OnConflict.IGNORE: + return 'INSERT IGNORE INTO' + return super().insert_statement(on_conflict=on_conflict) def lookup_cast(self, lookup_type, internal_type=None): lookup = '%s' @@ -388,3 +391,27 @@ class DatabaseOperations(BaseDatabaseOperations): if getattr(expression, 'conditional', False): return False return super().conditional_expression_supported_in_where_clause(expression) + + def on_conflict_suffix_sql(self, fields, on_conflict, update_fields, unique_fields): + if on_conflict == OnConflict.UPDATE: + conflict_suffix_sql = 'ON DUPLICATE KEY UPDATE %(fields)s' + field_sql = '%(field)s = VALUES(%(field)s)' + # The use of VALUES() is deprecated in MySQL 8.0.20+. Instead, use + # aliases for the new row and its columns available in MySQL + # 8.0.19+. + if not self.connection.mysql_is_mariadb: + if self.connection.mysql_version >= (8, 0, 19): + conflict_suffix_sql = f'AS new {conflict_suffix_sql}' + field_sql = '%(field)s = new.%(field)s' + # VALUES() was renamed to VALUE() in MariaDB 10.3.3+. + elif self.connection.mysql_version >= (10, 3, 3): + field_sql = '%(field)s = VALUE(%(field)s)' + + fields = ', '.join([ + field_sql % {'field': field} + for field in map(self.quote_name, update_fields) + ]) + return conflict_suffix_sql % {'fields': fields} + return super().on_conflict_suffix_sql( + fields, on_conflict, update_fields, unique_fields, + ) |