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>
|
||||
Wiley Kestner <wiley.kestner@gmail.com>
|
||||
Wiliam Alves de Souza <wiliamsouza83@gmail.com>
|
||||
William Schwartz <wkschwartz@gmail.com>
|
||||
Will Hardy <django@willhardy.com.au>
|
||||
Wilson Miner <wminer@gmail.com>
|
||||
wojtek
|
||||
|
|
|
@ -411,7 +411,7 @@ class QuerySet(object):
|
|||
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
|
||||
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
|
||||
# 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
|
||||
# on these for now because they are relatively rare cases.
|
||||
assert batch_size is None or batch_size > 0
|
||||
if self.model._meta.parents:
|
||||
raise ValueError("Can't bulk create an inherited model")
|
||||
# Check that the parents share the same concrete model with the our
|
||||
# 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:
|
||||
return objs
|
||||
self._for_write = True
|
||||
connection = connections[self.db]
|
||||
fields = self.model._meta.local_concrete_fields
|
||||
fields = self.model._meta.concrete_fields
|
||||
objs = list(objs)
|
||||
self._populate_pk_values(objs)
|
||||
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.
|
||||
* 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
|
||||
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.
|
||||
|
|
|
@ -365,6 +365,9 @@ Management Commands
|
|||
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>`
|
||||
option for interacting with databases that store datetimes in local time and
|
||||
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)
|
||||
|
||||
|
||||
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):
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
|
|
|
@ -7,7 +7,10 @@ from django.test import (
|
|||
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):
|
||||
|
@ -35,21 +38,36 @@ class BulkCreateTests(TestCase):
|
|||
with self.assertNumQueries(1):
|
||||
Country.objects.bulk_create(self.data)
|
||||
|
||||
def test_inheritance(self):
|
||||
Restaurant.objects.bulk_create([
|
||||
Restaurant(name="Nicholas's")
|
||||
])
|
||||
self.assertQuerysetEqual(Restaurant.objects.all(), [
|
||||
"Nicholas's",
|
||||
], attrgetter("name"))
|
||||
with self.assertRaises(ValueError):
|
||||
def test_multi_table_inheritance_unsupported(self):
|
||||
expected_message = "Can't bulk create a multi-table inherited model"
|
||||
with self.assertRaisesMessage(ValueError, expected_message):
|
||||
Pizzeria.objects.bulk_create([
|
||||
Pizzeria(name="The Art of Pizza")
|
||||
Pizzeria(name="The Art of Pizza"),
|
||||
])
|
||||
self.assertQuerysetEqual(Pizzeria.objects.all(), [])
|
||||
self.assertQuerysetEqual(Restaurant.objects.all(), [
|
||||
"Nicholas's",
|
||||
], attrgetter("name"))
|
||||
with self.assertRaisesMessage(ValueError, expected_message):
|
||||
ProxyMultiCountry.objects.bulk_create([
|
||||
ProxyMultiCountry(name="Fillory", iso_two_letter="FL"),
|
||||
])
|
||||
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):
|
||||
State.objects.bulk_create([
|
||||
|
|
Loading…
Reference in New Issue