-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Support for bulk_update #4
Comments
Add "chain" code to change UpdateQuery to CpkUpdateQuery. class CPkQueryMixin():
:
###########################
# override
###########################
def chain(self, klass=None):
cpk_klass = klass
if klass == Query:
cpk_klass = CPkQuery
elif klass == UpdateQuery:
cpk_klass = CPkUpdateQuery
elif klass == DeleteQuery:
cpk_klass = CPkDeleteQuery
return super().chain(klass=cpk_klass) This is not the main problem. The problem is "pk=obj.pk" in When class. class QuerySet:
:
def bulk_update(self, objs, fields, batch_size=None):
"""
Update the given fields in each of the given objects in the database.
"""
if batch_size is not None and batch_size < 0:
raise ValueError('Batch size must be a positive integer.')
if not fields:
raise ValueError('Field names must be given to bulk_update().')
objs = tuple(objs)
if any(obj.pk is None for obj in objs):
raise ValueError('All bulk_update() objects must have a primary key set.')
fields = [self.model._meta.get_field(name) for name in fields]
if any(not f.concrete or f.many_to_many for f in fields):
raise ValueError('bulk_update() can only be used with concrete fields.')
if any(f.primary_key for f in fields):
raise ValueError('bulk_update() cannot be used with primary key fields.')
if not objs:
return
# PK is used twice in the resulting update query, once in the filter
# and once in the WHEN. Each field will also have one CAST.
max_batch_size = connections[self.db].ops.bulk_batch_size(['pk', 'pk'] + fields, objs)
batch_size = min(batch_size, max_batch_size) if batch_size else max_batch_size
requires_casting = connections[self.db].features.requires_casted_case_in_updates
batches = (objs[i:i + batch_size] for i in range(0, len(objs), batch_size))
updates = []
for batch_objs in batches:
update_kwargs = {}
for field in fields:
when_statements = []
for obj in batch_objs:
attr = getattr(obj, field.attname)
if not isinstance(attr, Expression):
attr = Value(attr, output_field=field)
when_statements.append(When(pk=obj.pk, then=attr)) # This is the problem!! Need to treate CompositePK
case_statement = Case(*when_statements, output_field=field)
if requires_casting:
case_statement = Cast(case_statement, output_field=field)
update_kwargs[field.attname] = case_statement
updates.append(([obj.pk for obj in batch_objs], update_kwargs))
with transaction.atomic(using=self.db, savepoint=False):
for pks, update_kwargs in updates:
self.filter(pk__in=pks).update(**update_kwargs)
bulk_update.alters_data = True |
Merged
Release v1.0.2 1. Override QuerySet.bulk_update to change pk lookup for When classclass CPkQuerySet(QuerySet):
###########################
# override
###########################
:
def bulk_update(self, objs, fields, batch_size=None):
:
# CHANGE S
#when_statements.append(When(pk=obj.pk, then=attr))
lookups = obj.get_pk_lookups()
when_statements.append(When(**lookups, then=attr))
# CHANGE E
: 2. Add get_pk_lookups method to CpkModelclass CPkModelMixin:
:
def get_pk_lookups(self):
if self.has_compositepk:
keys = self.pkeys
vals = self.pkvals
return { key.attname:val for key, val in zip(keys, vals)}
else:
return { 'pk':self.pk }
: |
# for free
to join this conversation on GitHub.
Already have an account?
# to comment
CPkQuerySet.bulk_update fails.
Need to change UpdateQuery To CPkUpdateQuery
The text was updated successfully, but these errors were encountered: