summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Shachnev <mitya57@gmail.com>2025-03-16 20:50:45 +0300
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2025-03-26 09:55:09 +0100
commit77b4ecbd53635b94d3685d16af9e8b2f96cf952c (patch)
tree9d7ea315f3d6c951d6be32e8bb36b3ffcc2fcc1b
parentc75fbe843079ca249d7015926490dd21107e63a4 (diff)
Fixed #36260 -- Made bulk_create() work with DB-generated primary keys.
Co-authored-by: Simon Charette <charette.s@gmail.com>
-rw-r--r--django/db/models/query.py7
-rw-r--r--docs/ref/models/querysets.txt9
-rw-r--r--tests/bulk_create/models.py4
-rw-r--r--tests/bulk_create/tests.py7
4 files changed, 21 insertions, 6 deletions
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 175073b961..9f2332a60e 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -23,7 +23,7 @@ from django.db import (
from django.db.models import AutoField, DateField, DateTimeField, Field, sql
from django.db.models.constants import LOOKUP_SEP, OnConflict
from django.db.models.deletion import Collector
-from django.db.models.expressions import Case, F, Value, When
+from django.db.models.expressions import Case, DatabaseDefault, F, Value, When
from django.db.models.functions import Cast, Trunc
from django.db.models.query_utils import FilteredRelation, Q
from django.db.models.sql.constants import GET_ITERATOR_CHUNK_SIZE, ROW_COUNT
@@ -789,7 +789,10 @@ class QuerySet(AltersData):
objs = list(objs)
self._prepare_for_bulk_create(objs)
with transaction.atomic(using=self.db, savepoint=False):
- objs_without_pk, objs_with_pk = partition(lambda o: o._is_pk_set(), objs)
+ objs_without_pk, objs_with_pk = partition(
+ lambda o: o._is_pk_set() and not isinstance(o.pk, DatabaseDefault),
+ objs,
+ )
if objs_with_pk:
returned_columns = self._batched_insert(
objs_with_pk,
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index 91ce0bac69..e16d6668ee 100644
--- a/docs/ref/models/querysets.txt
+++ b/docs/ref/models/querysets.txt
@@ -2427,10 +2427,11 @@ 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` and
- ``ignore_conflicts`` is False, the primary key attribute can only be
- retrieved on certain databases (currently PostgreSQL, MariaDB, and SQLite
- 3.35+). On other databases, it will not be set.
+* If the model's primary key is an :class:`~django.db.models.AutoField` or has
+ a :attr:`~django.db.models.Field.db_default` value, and ``ignore_conflicts``
+ is ``False``, the primary key attribute can only be retrieved on certain
+ databases (currently PostgreSQL, MariaDB, 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
diff --git a/tests/bulk_create/models.py b/tests/bulk_create/models.py
index f0df9da66e..4b74b7ef56 100644
--- a/tests/bulk_create/models.py
+++ b/tests/bulk_create/models.py
@@ -147,3 +147,7 @@ class RelatedModel(models.Model):
class DbDefaultModel(models.Model):
name = models.CharField(max_length=10)
created_at = models.DateTimeField(db_default=Now())
+
+
+class DbDefaultPrimaryKey(models.Model):
+ id = models.DateTimeField(primary_key=True, db_default=Now())
diff --git a/tests/bulk_create/tests.py b/tests/bulk_create/tests.py
index 83ff8e4514..9bcf92e4cf 100644
--- a/tests/bulk_create/tests.py
+++ b/tests/bulk_create/tests.py
@@ -1,3 +1,4 @@
+from datetime import datetime
from math import ceil
from operator import attrgetter
@@ -23,6 +24,7 @@ from .models import (
BigAutoFieldModel,
Country,
DbDefaultModel,
+ DbDefaultPrimaryKey,
FieldsWithDbColumns,
NoFields,
NullableFields,
@@ -866,3 +868,8 @@ class BulkCreateTests(TestCase):
ctx[0]["sql"].count(created_at_quoted_name),
2 if connection.features.can_return_rows_from_bulk_insert else 1,
)
+
+ @skipUnlessDBFeature("can_return_rows_from_bulk_insert")
+ def test_db_default_primary_key(self):
+ (obj,) = DbDefaultPrimaryKey.objects.bulk_create([DbDefaultPrimaryKey()])
+ self.assertIsInstance(obj.id, datetime)