django-bulk-hooks 0.1.183__tar.gz → 0.1.185__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of django-bulk-hooks might be problematic. Click here for more details.
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/PKG-INFO +1 -1
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/queryset.py +61 -8
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/pyproject.toml +1 -1
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/LICENSE +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/README.md +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/__init__.py +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/conditions.py +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/constants.py +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/context.py +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/decorators.py +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/engine.py +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/enums.py +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/handler.py +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/manager.py +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/models.py +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/priority.py +0 -0
- {django_bulk_hooks-0.1.183 → django_bulk_hooks-0.1.185}/django_bulk_hooks/registry.py +0 -0
|
@@ -537,6 +537,19 @@ class HookQuerySet(models.QuerySet):
|
|
|
537
537
|
model_cls = self.model
|
|
538
538
|
inheritance_chain = self._get_inheritance_chain()
|
|
539
539
|
|
|
540
|
+
# Remove custom hook kwargs before passing to Django internals
|
|
541
|
+
django_kwargs = {
|
|
542
|
+
k: v
|
|
543
|
+
for k, v in kwargs.items()
|
|
544
|
+
if k not in ["bypass_hooks", "bypass_validation"]
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
# Safety check to prevent infinite recursion
|
|
548
|
+
if len(inheritance_chain) > 10: # Arbitrary limit to prevent infinite loops
|
|
549
|
+
raise ValueError(
|
|
550
|
+
"Inheritance chain too deep - possible infinite recursion detected"
|
|
551
|
+
)
|
|
552
|
+
|
|
540
553
|
# Group fields by model in the inheritance chain
|
|
541
554
|
field_groups = {}
|
|
542
555
|
for field_name in fields:
|
|
@@ -549,32 +562,72 @@ class HookQuerySet(models.QuerySet):
|
|
|
549
562
|
field_groups[model].append(field_name)
|
|
550
563
|
break
|
|
551
564
|
|
|
552
|
-
#
|
|
565
|
+
# Process in batches
|
|
566
|
+
batch_size = django_kwargs.get("batch_size") or len(objs)
|
|
553
567
|
total_updated = 0
|
|
568
|
+
|
|
569
|
+
with transaction.atomic(using=self.db, savepoint=False):
|
|
570
|
+
for i in range(0, len(objs), batch_size):
|
|
571
|
+
batch = objs[i : i + batch_size]
|
|
572
|
+
batch_result = self._process_mti_bulk_update_batch(
|
|
573
|
+
batch, field_groups, inheritance_chain, **django_kwargs
|
|
574
|
+
)
|
|
575
|
+
total_updated += batch_result
|
|
576
|
+
|
|
577
|
+
return total_updated
|
|
578
|
+
|
|
579
|
+
def _process_mti_bulk_update_batch(self, batch, field_groups, inheritance_chain, **kwargs):
|
|
580
|
+
"""
|
|
581
|
+
Process a single batch of objects for MTI bulk update.
|
|
582
|
+
Updates each table in the inheritance chain for the batch.
|
|
583
|
+
"""
|
|
584
|
+
total_updated = 0
|
|
585
|
+
|
|
586
|
+
# Update each table in the inheritance chain
|
|
554
587
|
for model, model_fields in field_groups.items():
|
|
555
588
|
if not model_fields:
|
|
556
589
|
continue
|
|
557
590
|
|
|
558
|
-
#
|
|
559
|
-
|
|
591
|
+
# For MTI, we need to handle parent links correctly
|
|
592
|
+
# The root model (first in chain) has its own PK
|
|
593
|
+
# Child models use the parent link to reference the root PK
|
|
594
|
+
if model == inheritance_chain[0]:
|
|
595
|
+
# Root model - use primary keys directly
|
|
596
|
+
pks = [obj.pk for obj in batch]
|
|
597
|
+
filter_field = 'pk'
|
|
598
|
+
else:
|
|
599
|
+
# Child model - use parent link field
|
|
600
|
+
parent_link = None
|
|
601
|
+
for parent_model in inheritance_chain:
|
|
602
|
+
if parent_model in model._meta.parents:
|
|
603
|
+
parent_link = model._meta.parents[parent_model]
|
|
604
|
+
break
|
|
605
|
+
|
|
606
|
+
if parent_link is None:
|
|
607
|
+
# This shouldn't happen in proper MTI, but handle gracefully
|
|
608
|
+
continue
|
|
609
|
+
|
|
610
|
+
# Get the parent link values (these should be the same as the root PKs)
|
|
611
|
+
pks = [getattr(obj, parent_link.attname) for obj in batch]
|
|
612
|
+
filter_field = parent_link.attname
|
|
560
613
|
|
|
561
614
|
if pks:
|
|
562
615
|
base_qs = model._base_manager.using(self.db)
|
|
563
616
|
|
|
564
|
-
# Build CASE statements for each field
|
|
617
|
+
# Build CASE statements for each field to perform a single bulk update
|
|
565
618
|
case_statements = {}
|
|
566
619
|
for field_name in model_fields:
|
|
567
620
|
field = model._meta.get_field(field_name)
|
|
568
621
|
when_statements = []
|
|
569
622
|
|
|
570
|
-
for pk, obj in zip(pks,
|
|
623
|
+
for pk, obj in zip(pks, batch):
|
|
571
624
|
value = getattr(obj, field_name)
|
|
572
|
-
when_statements.append(When(pk
|
|
625
|
+
when_statements.append(When(**{filter_field: pk}, then=Value(value, output_field=field)))
|
|
573
626
|
|
|
574
627
|
case_statements[field_name] = Case(*when_statements, output_field=field)
|
|
575
628
|
|
|
576
|
-
# Execute
|
|
577
|
-
updated_count = base_qs.filter(
|
|
629
|
+
# Execute a single bulk update for all objects in this model
|
|
630
|
+
updated_count = base_qs.filter(**{f"{filter_field}__in": pks}).update(**case_statements)
|
|
578
631
|
total_updated += updated_count
|
|
579
632
|
|
|
580
633
|
return total_updated
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "django-bulk-hooks"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.185"
|
|
4
4
|
description = "Hook-style hooks for Django bulk operations like bulk_create and bulk_update."
|
|
5
5
|
authors = ["Konrad Beck <konrad.beck@merchantcapital.co.za>"]
|
|
6
6
|
readme = "README.md"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|