Fixed #23646 -- Added QuerySet.bulk_update() to efficiently update many models.

This commit is contained in:
Tom Forbes 2018-09-18 21:14:44 +01:00 committed by Tim Graham
parent 7b159df942
commit 9cbdb44014
11 changed files with 359 additions and 8 deletions

View file

@ -56,9 +56,9 @@ class Migration(migrations.Migration):
name='OtherTypesArrayModel',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('ips', ArrayField(models.GenericIPAddressField(), size=None)),
('uuids', ArrayField(models.UUIDField(), size=None)),
('decimals', ArrayField(models.DecimalField(max_digits=5, decimal_places=2), size=None)),
('ips', ArrayField(models.GenericIPAddressField(), size=None, default=list)),
('uuids', ArrayField(models.UUIDField(), size=None, default=list)),
('decimals', ArrayField(models.DecimalField(max_digits=5, decimal_places=2), size=None, default=list)),
('tags', ArrayField(TagField(), blank=True, null=True, size=None)),
('json', ArrayField(JSONField(default={}), default=[])),
('int_ranges', ArrayField(IntegerRangeField(), null=True, blank=True)),

View file

@ -63,9 +63,9 @@ class NestedIntegerArrayModel(PostgreSQLModel):
class OtherTypesArrayModel(PostgreSQLModel):
ips = ArrayField(models.GenericIPAddressField())
uuids = ArrayField(models.UUIDField())
decimals = ArrayField(models.DecimalField(max_digits=5, decimal_places=2))
ips = ArrayField(models.GenericIPAddressField(), default=list)
uuids = ArrayField(models.UUIDField(), default=list)
decimals = ArrayField(models.DecimalField(max_digits=5, decimal_places=2), default=list)
tags = ArrayField(TagField(), blank=True, null=True)
json = ArrayField(JSONField(default=dict), default=list)
int_ranges = ArrayField(IntegerRangeField(), blank=True, null=True)

View file

@ -0,0 +1,34 @@
from datetime import date
from . import PostgreSQLTestCase
from .models import (
HStoreModel, IntegerArrayModel, JSONModel, NestedIntegerArrayModel,
NullableIntegerArrayModel, OtherTypesArrayModel, RangesModel,
)
try:
from psycopg2.extras import NumericRange, DateRange
except ImportError:
pass # psycopg2 isn't installed.
class BulkSaveTests(PostgreSQLTestCase):
def test_bulk_update(self):
test_data = [
(IntegerArrayModel, 'field', [], [1, 2, 3]),
(NullableIntegerArrayModel, 'field', [1, 2, 3], None),
(JSONModel, 'field', {'a': 'b'}, {'c': 'd'}),
(NestedIntegerArrayModel, 'field', [], [[1, 2, 3]]),
(HStoreModel, 'field', {}, {1: 2}),
(RangesModel, 'ints', None, NumericRange(lower=1, upper=10)),
(RangesModel, 'dates', None, DateRange(lower=date.today(), upper=date.today())),
(OtherTypesArrayModel, 'ips', [], ['1.2.3.4']),
(OtherTypesArrayModel, 'json', [], [{'a': 'b'}])
]
for Model, field, initial, new in test_data:
with self.subTest(model=Model, field=field):
instances = Model.objects.bulk_create(Model(**{field: initial}) for _ in range(20))
for instance in instances:
setattr(instance, field, new)
Model.objects.bulk_update(instances, [field])
self.assertSequenceEqual(Model.objects.filter(**{field: new}), instances)