Skip to content

Commit f0ae9cb

Browse files
committed
Customize collector to support deleting elements
1 parent 0af435a commit f0ae9cb

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

cpkmodel/collector.py

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
from collections import Counter
2+
from operator import attrgetter
3+
4+
from django.db import transaction
5+
from django.db.models import signals
6+
from django.db.models.deletion import Collector
7+
8+
from . import cpkquery as sql
9+
10+
11+
class CpkCollector(Collector):
12+
def delete(self):
13+
# sort instance collections
14+
for model, instances in self.data.items():
15+
self.data[model] = sorted(instances, key=attrgetter("pk"))
16+
17+
# if possible, bring the models in an order suitable for databases that
18+
# don't support transactions or cannot defer constraint checks until the
19+
# end of a transaction.
20+
self.sort()
21+
# number of objects deleted for each model label
22+
deleted_counter = Counter()
23+
24+
# Optimize for the case with a single obj and no dependencies
25+
if len(self.data) == 1 and len(instances) == 1:
26+
instance = list(instances)[0]
27+
if self.can_fast_delete(instance):
28+
with transaction.mark_for_rollback_on_error(self.using):
29+
count = sql.CPkDeleteQuery(model).delete_batch([instance.pk], self.using)
30+
setattr(instance, model._meta.pk.attname, None)
31+
return count, {model._meta.label: count}
32+
33+
with transaction.atomic(using=self.using, savepoint=False):
34+
# send pre_delete signals
35+
for model, obj in self.instances_with_model():
36+
if not model._meta.auto_created:
37+
signals.pre_delete.send(sender=model, instance=obj, using=self.using)
38+
39+
# fast deletes
40+
for qs in self.fast_deletes:
41+
count = qs._raw_delete(using=self.using)
42+
if count:
43+
deleted_counter[qs.model._meta.label] += count
44+
45+
# update fields
46+
for model, instances_for_fieldvalues in self.field_updates.items():
47+
for (field, value), instances in instances_for_fieldvalues.items():
48+
query = sql.CPkUpdateQuery(model)
49+
query.update_batch([obj.pk for obj in instances], {field.name: value}, self.using)
50+
51+
# reverse instance collections
52+
for instances in self.data.values():
53+
instances.reverse()
54+
55+
# delete instances
56+
for model, instances in self.data.items():
57+
query = sql.CPkDeleteQuery(model)
58+
pk_list = [obj.pk for obj in instances]
59+
count = query.delete_batch(pk_list, self.using)
60+
if count:
61+
deleted_counter[model._meta.label] += count
62+
63+
if not model._meta.auto_created:
64+
for obj in instances:
65+
signals.post_delete.send(sender=model, instance=obj, using=self.using)
66+
67+
# update collected instances
68+
for instances_for_fieldvalues in self.field_updates.values():
69+
for (field, value), instances in instances_for_fieldvalues.items():
70+
for obj in instances:
71+
setattr(obj, field.attname, value)
72+
for model, instances in self.data.items():
73+
for instance in instances:
74+
setattr(instance, model._meta.pk.attname, None)
75+
return sum(deleted_counter.values()), dict(deleted_counter)

cpkmodel/cpkmodel.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from django.db import router
22
from django.db.models import Model
33
from django.db.models.base import ModelBase
4-
from django.db.models.deletion import Collector
54

5+
from .collector import CpkCollector as Collector
66
from .compositekey import CompositeKey
77
from .constants import CPK_SEP
88
from .cpkquery import CPkQuerySet

0 commit comments

Comments
 (0)