Fixed #24997 -- Enabled bulk_create() on proxy models
This commit is contained in:
parent
fedef7b2c6
commit
9a5cfa05a0
1
AUTHORS
1
AUTHORS
|
@ -724,6 +724,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Wiktor Kołodziej <wiktor@pykonik.org>
|
Wiktor Kołodziej <wiktor@pykonik.org>
|
||||||
Wiley Kestner <wiley.kestner@gmail.com>
|
Wiley Kestner <wiley.kestner@gmail.com>
|
||||||
Wiliam Alves de Souza <wiliamsouza83@gmail.com>
|
Wiliam Alves de Souza <wiliamsouza83@gmail.com>
|
||||||
|
William Schwartz <wkschwartz@gmail.com>
|
||||||
Will Hardy <django@willhardy.com.au>
|
Will Hardy <django@willhardy.com.au>
|
||||||
Wilson Miner <wminer@gmail.com>
|
Wilson Miner <wminer@gmail.com>
|
||||||
wojtek
|
wojtek
|
||||||
|
|
|
@ -411,7 +411,7 @@ class QuerySet(object):
|
||||||
Inserts each of the instances into the database. This does *not* call
|
Inserts each of the instances into the database. This does *not* call
|
||||||
save() on each of the instances, does not send any pre/post save
|
save() on each of the instances, does not send any pre/post save
|
||||||
signals, and does not set the primary key attribute if it is an
|
signals, and does not set the primary key attribute if it is an
|
||||||
autoincrement field.
|
autoincrement field. Multi-table models are not supported.
|
||||||
"""
|
"""
|
||||||
# So this case is fun. When you bulk insert you don't get the primary
|
# So this case is fun. When you bulk insert you don't get the primary
|
||||||
# keys back (if it's an autoincrement), so you can't insert into the
|
# keys back (if it's an autoincrement), so you can't insert into the
|
||||||
|
@ -423,13 +423,18 @@ class QuerySet(object):
|
||||||
# this by using RETURNING clause for the insert query. We're punting
|
# this by using RETURNING clause for the insert query. We're punting
|
||||||
# on these for now because they are relatively rare cases.
|
# on these for now because they are relatively rare cases.
|
||||||
assert batch_size is None or batch_size > 0
|
assert batch_size is None or batch_size > 0
|
||||||
if self.model._meta.parents:
|
# Check that the parents share the same concrete model with the our
|
||||||
raise ValueError("Can't bulk create an inherited model")
|
# model to detect the inheritance pattern ConcreteGrandParent ->
|
||||||
|
# MultiTableParent -> ProxyChild. Simply checking self.model._meta.proxy
|
||||||
|
# would not identify that case as involving multiple tables.
|
||||||
|
for parent in self.model._meta.get_parent_list():
|
||||||
|
if parent._meta.concrete_model is not self.model._meta.concrete_model:
|
||||||
|
raise ValueError("Can't bulk create a multi-table inherited model")
|
||||||
if not objs:
|
if not objs:
|
||||||
return objs
|
return objs
|
||||||
self._for_write = True
|
self._for_write = True
|
||||||
connection = connections[self.db]
|
connection = connections[self.db]
|
||||||
fields = self.model._meta.local_concrete_fields
|
fields = self.model._meta.concrete_fields
|
||||||
objs = list(objs)
|
objs = list(objs)
|
||||||
self._populate_pk_values(objs)
|
self._populate_pk_values(objs)
|
||||||
with transaction.atomic(using=self.db, savepoint=False):
|
with transaction.atomic(using=self.db, savepoint=False):
|
||||||
|
|
|
@ -1768,6 +1768,10 @@ This has a number of caveats though:
|
||||||
does not retrieve and set the primary key attribute, as ``save()`` does.
|
does not retrieve and set the primary key attribute, as ``save()`` does.
|
||||||
* It does not work with many-to-many relationships.
|
* It does not work with many-to-many relationships.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.9
|
||||||
|
|
||||||
|
Support for using ``bulk_create()`` with proxy models was added.
|
||||||
|
|
||||||
The ``batch_size`` parameter controls how many objects are created in single
|
The ``batch_size`` parameter controls how many objects are created in single
|
||||||
query. The default is to create all objects in one batch, except for SQLite
|
query. The default is to create all objects in one batch, except for SQLite
|
||||||
where the default is such that at most 999 variables per query are used.
|
where the default is such that at most 999 variables per query are used.
|
||||||
|
|
|
@ -365,6 +365,9 @@ Management Commands
|
||||||
Models
|
Models
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
|
* :meth:`QuerySet.bulk_create() <django.db.models.query.QuerySet.bulk_create>`
|
||||||
|
now works on proxy models.
|
||||||
|
|
||||||
* Database configuration gained a :setting:`TIME_ZONE <DATABASE-TIME_ZONE>`
|
* Database configuration gained a :setting:`TIME_ZONE <DATABASE-TIME_ZONE>`
|
||||||
option for interacting with databases that store datetimes in local time and
|
option for interacting with databases that store datetimes in local time and
|
||||||
don't support time zones when :setting:`USE_TZ` is ``True``.
|
don't support time zones when :setting:`USE_TZ` is ``True``.
|
||||||
|
|
|
@ -6,6 +6,25 @@ class Country(models.Model):
|
||||||
iso_two_letter = models.CharField(max_length=2)
|
iso_two_letter = models.CharField(max_length=2)
|
||||||
|
|
||||||
|
|
||||||
|
class ProxyCountry(Country):
|
||||||
|
class Meta:
|
||||||
|
proxy = True
|
||||||
|
|
||||||
|
|
||||||
|
class ProxyProxyCountry(ProxyCountry):
|
||||||
|
class Meta:
|
||||||
|
proxy = True
|
||||||
|
|
||||||
|
|
||||||
|
class ProxyMultiCountry(ProxyCountry):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ProxyMultiProxyCountry(ProxyMultiCountry):
|
||||||
|
class Meta:
|
||||||
|
proxy = True
|
||||||
|
|
||||||
|
|
||||||
class Place(models.Model):
|
class Place(models.Model):
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,10 @@ from django.test import (
|
||||||
TestCase, override_settings, skipIfDBFeature, skipUnlessDBFeature,
|
TestCase, override_settings, skipIfDBFeature, skipUnlessDBFeature,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .models import Country, Pizzeria, Restaurant, State, TwoFields
|
from .models import (
|
||||||
|
Country, Pizzeria, ProxyCountry, ProxyMultiCountry, ProxyMultiProxyCountry,
|
||||||
|
ProxyProxyCountry, Restaurant, State, TwoFields,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BulkCreateTests(TestCase):
|
class BulkCreateTests(TestCase):
|
||||||
|
@ -35,21 +38,36 @@ class BulkCreateTests(TestCase):
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
Country.objects.bulk_create(self.data)
|
Country.objects.bulk_create(self.data)
|
||||||
|
|
||||||
def test_inheritance(self):
|
def test_multi_table_inheritance_unsupported(self):
|
||||||
Restaurant.objects.bulk_create([
|
expected_message = "Can't bulk create a multi-table inherited model"
|
||||||
Restaurant(name="Nicholas's")
|
with self.assertRaisesMessage(ValueError, expected_message):
|
||||||
])
|
|
||||||
self.assertQuerysetEqual(Restaurant.objects.all(), [
|
|
||||||
"Nicholas's",
|
|
||||||
], attrgetter("name"))
|
|
||||||
with self.assertRaises(ValueError):
|
|
||||||
Pizzeria.objects.bulk_create([
|
Pizzeria.objects.bulk_create([
|
||||||
Pizzeria(name="The Art of Pizza")
|
Pizzeria(name="The Art of Pizza"),
|
||||||
])
|
])
|
||||||
self.assertQuerysetEqual(Pizzeria.objects.all(), [])
|
with self.assertRaisesMessage(ValueError, expected_message):
|
||||||
self.assertQuerysetEqual(Restaurant.objects.all(), [
|
ProxyMultiCountry.objects.bulk_create([
|
||||||
"Nicholas's",
|
ProxyMultiCountry(name="Fillory", iso_two_letter="FL"),
|
||||||
], attrgetter("name"))
|
])
|
||||||
|
with self.assertRaisesMessage(ValueError, expected_message):
|
||||||
|
ProxyMultiProxyCountry.objects.bulk_create([
|
||||||
|
ProxyMultiProxyCountry(name="Fillory", iso_two_letter="FL"),
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_proxy_inheritance_supported(self):
|
||||||
|
ProxyCountry.objects.bulk_create([
|
||||||
|
ProxyCountry(name="Qwghlm", iso_two_letter="QW"),
|
||||||
|
Country(name="Tortall", iso_two_letter="TA"),
|
||||||
|
])
|
||||||
|
self.assertQuerysetEqual(ProxyCountry.objects.all(), {
|
||||||
|
"Qwghlm", "Tortall"
|
||||||
|
}, attrgetter("name"), ordered=False)
|
||||||
|
|
||||||
|
ProxyProxyCountry.objects.bulk_create([
|
||||||
|
ProxyProxyCountry(name="Neitherlands", iso_two_letter="NT"),
|
||||||
|
])
|
||||||
|
self.assertQuerysetEqual(ProxyProxyCountry.objects.all(), {
|
||||||
|
"Qwghlm", "Tortall", "Neitherlands",
|
||||||
|
}, attrgetter("name"), ordered=False)
|
||||||
|
|
||||||
def test_non_auto_increment_pk(self):
|
def test_non_auto_increment_pk(self):
|
||||||
State.objects.bulk_create([
|
State.objects.bulk_create([
|
||||||
|
|
Loading…
Reference in New Issue