mirror of
https://github.com/django/django.git
synced 2025-05-23 07:16:29 +00:00
Fixed #36260 -- Made bulk_create() work with DB-generated primary keys.
Co-authored-by: Simon Charette <charette.s@gmail.com>
This commit is contained in:
parent
c75fbe8430
commit
77b4ecbd53
@ -23,7 +23,7 @@ from django.db import (
|
|||||||
from django.db.models import AutoField, DateField, DateTimeField, Field, sql
|
from django.db.models import AutoField, DateField, DateTimeField, Field, sql
|
||||||
from django.db.models.constants import LOOKUP_SEP, OnConflict
|
from django.db.models.constants import LOOKUP_SEP, OnConflict
|
||||||
from django.db.models.deletion import Collector
|
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.functions import Cast, Trunc
|
||||||
from django.db.models.query_utils import FilteredRelation, Q
|
from django.db.models.query_utils import FilteredRelation, Q
|
||||||
from django.db.models.sql.constants import GET_ITERATOR_CHUNK_SIZE, ROW_COUNT
|
from django.db.models.sql.constants import GET_ITERATOR_CHUNK_SIZE, ROW_COUNT
|
||||||
@ -789,7 +789,10 @@ class QuerySet(AltersData):
|
|||||||
objs = list(objs)
|
objs = list(objs)
|
||||||
self._prepare_for_bulk_create(objs)
|
self._prepare_for_bulk_create(objs)
|
||||||
with transaction.atomic(using=self.db, savepoint=False):
|
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:
|
if objs_with_pk:
|
||||||
returned_columns = self._batched_insert(
|
returned_columns = self._batched_insert(
|
||||||
objs_with_pk,
|
objs_with_pk,
|
||||||
|
@ -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
|
* The model's ``save()`` method will not be called, and the ``pre_save`` and
|
||||||
``post_save`` signals will not be sent.
|
``post_save`` signals will not be sent.
|
||||||
* It does not work with child models in a multi-table inheritance scenario.
|
* 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
|
* If the model's primary key is an :class:`~django.db.models.AutoField` or has
|
||||||
``ignore_conflicts`` is False, the primary key attribute can only be
|
a :attr:`~django.db.models.Field.db_default` value, and ``ignore_conflicts``
|
||||||
retrieved on certain databases (currently PostgreSQL, MariaDB, and SQLite
|
is ``False``, the primary key attribute can only be retrieved on certain
|
||||||
3.35+). On other databases, it will not be set.
|
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 does not work with many-to-many relationships.
|
||||||
* It casts ``objs`` to a list, which fully evaluates ``objs`` if it's a
|
* 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
|
generator. The cast allows inspecting all objects so that any objects with a
|
||||||
|
@ -147,3 +147,7 @@ class RelatedModel(models.Model):
|
|||||||
class DbDefaultModel(models.Model):
|
class DbDefaultModel(models.Model):
|
||||||
name = models.CharField(max_length=10)
|
name = models.CharField(max_length=10)
|
||||||
created_at = models.DateTimeField(db_default=Now())
|
created_at = models.DateTimeField(db_default=Now())
|
||||||
|
|
||||||
|
|
||||||
|
class DbDefaultPrimaryKey(models.Model):
|
||||||
|
id = models.DateTimeField(primary_key=True, db_default=Now())
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from datetime import datetime
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ from .models import (
|
|||||||
BigAutoFieldModel,
|
BigAutoFieldModel,
|
||||||
Country,
|
Country,
|
||||||
DbDefaultModel,
|
DbDefaultModel,
|
||||||
|
DbDefaultPrimaryKey,
|
||||||
FieldsWithDbColumns,
|
FieldsWithDbColumns,
|
||||||
NoFields,
|
NoFields,
|
||||||
NullableFields,
|
NullableFields,
|
||||||
@ -866,3 +868,8 @@ class BulkCreateTests(TestCase):
|
|||||||
ctx[0]["sql"].count(created_at_quoted_name),
|
ctx[0]["sql"].count(created_at_quoted_name),
|
||||||
2 if connection.features.can_return_rows_from_bulk_insert else 1,
|
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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user