django-bulk-hooks 0.1.191__py3-none-any.whl → 0.1.192__py3-none-any.whl
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/queryset.py +0 -70
- {django_bulk_hooks-0.1.191.dist-info → django_bulk_hooks-0.1.192.dist-info}/METADATA +1 -1
- {django_bulk_hooks-0.1.191.dist-info → django_bulk_hooks-0.1.192.dist-info}/RECORD +5 -5
- {django_bulk_hooks-0.1.191.dist-info → django_bulk_hooks-0.1.192.dist-info}/LICENSE +0 -0
- {django_bulk_hooks-0.1.191.dist-info → django_bulk_hooks-0.1.192.dist-info}/WHEEL +0 -0
django_bulk_hooks/queryset.py
CHANGED
|
@@ -183,17 +183,9 @@ class HookQuerySetMixin:
|
|
|
183
183
|
"""
|
|
184
184
|
Bulk update objects in the database with MTI support.
|
|
185
185
|
"""
|
|
186
|
-
print(f"\n=== BULK UPDATE DEBUG ===")
|
|
187
|
-
print(f"Model: {self.model.__name__}")
|
|
188
|
-
print(f"Number of objects: {len(objs)}")
|
|
189
|
-
print(f"Fields: {fields}")
|
|
190
|
-
print(f"Bypass hooks: {bypass_hooks}")
|
|
191
|
-
print(f"Bypass validation: {bypass_validation}")
|
|
192
|
-
|
|
193
186
|
model_cls = self.model
|
|
194
187
|
|
|
195
188
|
if not objs:
|
|
196
|
-
print("No objects to update")
|
|
197
189
|
return []
|
|
198
190
|
|
|
199
191
|
if any(not isinstance(obj, model_cls) for obj in objs):
|
|
@@ -207,11 +199,6 @@ class HookQuerySetMixin:
|
|
|
207
199
|
if parent._meta.concrete_model is not model_cls._meta.concrete_model:
|
|
208
200
|
is_mti = True
|
|
209
201
|
break
|
|
210
|
-
|
|
211
|
-
print(f"Is MTI: {is_mti}")
|
|
212
|
-
print(f"Model concrete model: {model_cls._meta.concrete_model.__name__}")
|
|
213
|
-
for parent in model_cls._meta.all_parents:
|
|
214
|
-
print(f" Parent {parent.__name__}: concrete_model = {parent._meta.concrete_model.__name__}")
|
|
215
202
|
|
|
216
203
|
if not bypass_hooks:
|
|
217
204
|
# Load originals for hook comparison
|
|
@@ -238,14 +225,11 @@ class HookQuerySetMixin:
|
|
|
238
225
|
fields_set = set(fields)
|
|
239
226
|
fields_set.update(modified_fields)
|
|
240
227
|
fields = list(fields_set)
|
|
241
|
-
print(f"Modified fields detected: {modified_fields}")
|
|
242
228
|
|
|
243
229
|
# Handle MTI models differently
|
|
244
230
|
if is_mti:
|
|
245
|
-
print("Using MTI bulk update logic")
|
|
246
231
|
result = self._mti_bulk_update(objs, fields, **kwargs)
|
|
247
232
|
else:
|
|
248
|
-
print("Using standard Django bulk_update")
|
|
249
233
|
# For single-table models, use Django's built-in bulk_update
|
|
250
234
|
django_kwargs = {
|
|
251
235
|
k: v
|
|
@@ -257,7 +241,6 @@ class HookQuerySetMixin:
|
|
|
257
241
|
if not bypass_hooks:
|
|
258
242
|
engine.run(model_cls, AFTER_UPDATE, objs, originals, ctx=ctx)
|
|
259
243
|
|
|
260
|
-
print(f"Bulk update result: {result}")
|
|
261
244
|
return result
|
|
262
245
|
|
|
263
246
|
def _detect_modified_fields(self, new_instances, original_instances):
|
|
@@ -302,29 +285,20 @@ class HookQuerySetMixin:
|
|
|
302
285
|
Get the complete inheritance chain from root parent to current model.
|
|
303
286
|
Returns list of model classes in order: [RootParent, Parent, Child]
|
|
304
287
|
"""
|
|
305
|
-
print(f"\n=== GET INHERITANCE CHAIN DEBUG ===")
|
|
306
|
-
print(f"Current model: {self.model.__name__}")
|
|
307
|
-
|
|
308
288
|
chain = []
|
|
309
289
|
current_model = self.model
|
|
310
290
|
while current_model:
|
|
311
|
-
print(f"Processing model: {current_model.__name__}")
|
|
312
291
|
if not current_model._meta.proxy:
|
|
313
292
|
chain.append(current_model)
|
|
314
|
-
print(f" Added to chain: {current_model.__name__}")
|
|
315
|
-
else:
|
|
316
|
-
print(f" Skipped proxy model: {current_model.__name__}")
|
|
317
293
|
|
|
318
294
|
parents = [
|
|
319
295
|
parent
|
|
320
296
|
for parent in current_model._meta.parents.keys()
|
|
321
297
|
if not parent._meta.proxy
|
|
322
298
|
]
|
|
323
|
-
print(f" Parents: {[p.__name__ for p in parents]}")
|
|
324
299
|
current_model = parents[0] if parents else None
|
|
325
300
|
|
|
326
301
|
chain.reverse()
|
|
327
|
-
print(f"Final inheritance chain: {[m.__name__ for m in chain]}")
|
|
328
302
|
return chain
|
|
329
303
|
|
|
330
304
|
def _mti_bulk_create(self, objs, inheritance_chain=None, **kwargs):
|
|
@@ -567,14 +541,8 @@ class HookQuerySetMixin:
|
|
|
567
541
|
Custom bulk update implementation for MTI models.
|
|
568
542
|
Updates each table in the inheritance chain efficiently using Django's batch_size.
|
|
569
543
|
"""
|
|
570
|
-
print(f"\n=== MTI BULK UPDATE DEBUG ===")
|
|
571
|
-
print(f"Model: {self.model.__name__}")
|
|
572
|
-
print(f"Number of objects: {len(objs)}")
|
|
573
|
-
print(f"Fields to update: {fields}")
|
|
574
|
-
|
|
575
544
|
model_cls = self.model
|
|
576
545
|
inheritance_chain = self._get_inheritance_chain()
|
|
577
|
-
print(f"Inheritance chain: {[m.__name__ for m in inheritance_chain]}")
|
|
578
546
|
|
|
579
547
|
# Remove custom hook kwargs before passing to Django internals
|
|
580
548
|
django_kwargs = {
|
|
@@ -599,28 +567,20 @@ class HookQuerySetMixin:
|
|
|
599
567
|
if model not in field_groups:
|
|
600
568
|
field_groups[model] = []
|
|
601
569
|
field_groups[model].append(field_name)
|
|
602
|
-
print(f"Field '{field_name}' belongs to model '{model.__name__}'")
|
|
603
570
|
break
|
|
604
|
-
|
|
605
|
-
print(f"Field groups: {field_groups}")
|
|
606
571
|
|
|
607
572
|
# Process in batches
|
|
608
573
|
batch_size = django_kwargs.get("batch_size") or len(objs)
|
|
609
574
|
total_updated = 0
|
|
610
575
|
|
|
611
|
-
print(f"Processing in batches of size: {batch_size}")
|
|
612
|
-
|
|
613
576
|
with transaction.atomic(using=self.db, savepoint=False):
|
|
614
577
|
for i in range(0, len(objs), batch_size):
|
|
615
578
|
batch = objs[i : i + batch_size]
|
|
616
|
-
print(f"\n--- Processing batch {i//batch_size + 1} ({len(batch)} objects) ---")
|
|
617
579
|
batch_result = self._process_mti_bulk_update_batch(
|
|
618
580
|
batch, field_groups, inheritance_chain, **django_kwargs
|
|
619
581
|
)
|
|
620
582
|
total_updated += batch_result
|
|
621
|
-
print(f"Batch {i//batch_size + 1} updated {batch_result} rows")
|
|
622
583
|
|
|
623
|
-
print(f"\n=== TOTAL UPDATED: {total_updated} ===")
|
|
624
584
|
return total_updated
|
|
625
585
|
|
|
626
586
|
def _process_mti_bulk_update_batch(self, batch, field_groups, inheritance_chain, **kwargs):
|
|
@@ -630,9 +590,6 @@ class HookQuerySetMixin:
|
|
|
630
590
|
"""
|
|
631
591
|
total_updated = 0
|
|
632
592
|
|
|
633
|
-
print(f"Processing batch with {len(batch)} objects")
|
|
634
|
-
print(f"Field groups: {field_groups}")
|
|
635
|
-
|
|
636
593
|
# For MTI, we need to handle parent links correctly
|
|
637
594
|
# The root model (first in chain) has its own PK
|
|
638
595
|
# Child models use the parent link to reference the root PK
|
|
@@ -649,31 +606,21 @@ class HookQuerySetMixin:
|
|
|
649
606
|
|
|
650
607
|
if pk_value is not None:
|
|
651
608
|
root_pks.append(pk_value)
|
|
652
|
-
print(f"Found PK {pk_value} for object {obj}")
|
|
653
609
|
else:
|
|
654
|
-
print(f"WARNING: Object {obj} has no primary key (pk={getattr(obj, 'pk', None)}, id={getattr(obj, 'id', None)})")
|
|
655
610
|
continue
|
|
656
611
|
|
|
657
|
-
print(f"Root PKs to update: {root_pks}")
|
|
658
|
-
|
|
659
612
|
if not root_pks:
|
|
660
|
-
print("No valid primary keys found, skipping update")
|
|
661
613
|
return 0
|
|
662
614
|
|
|
663
615
|
# Update each table in the inheritance chain
|
|
664
616
|
for model, model_fields in field_groups.items():
|
|
665
|
-
print(f"\n--- Updating model: {model.__name__} ---")
|
|
666
|
-
print(f"Fields to update: {model_fields}")
|
|
667
|
-
|
|
668
617
|
if not model_fields:
|
|
669
|
-
print("No fields to update, skipping")
|
|
670
618
|
continue
|
|
671
619
|
|
|
672
620
|
if model == inheritance_chain[0]:
|
|
673
621
|
# Root model - use primary keys directly
|
|
674
622
|
pks = root_pks
|
|
675
623
|
filter_field = 'pk'
|
|
676
|
-
print(f"Root model - using PKs: {pks}")
|
|
677
624
|
else:
|
|
678
625
|
# Child model - use parent link field
|
|
679
626
|
parent_link = None
|
|
@@ -683,27 +630,19 @@ class HookQuerySetMixin:
|
|
|
683
630
|
break
|
|
684
631
|
|
|
685
632
|
if parent_link is None:
|
|
686
|
-
print(f"No parent link found for {model.__name__}, skipping")
|
|
687
633
|
continue
|
|
688
634
|
|
|
689
|
-
print(f"Parent link field: {parent_link.name} ({parent_link.attname})")
|
|
690
|
-
|
|
691
635
|
# For child models, the parent link values should be the same as root PKs
|
|
692
636
|
pks = root_pks
|
|
693
637
|
filter_field = parent_link.attname
|
|
694
|
-
print(f"Child model - using parent link values: {pks}")
|
|
695
638
|
|
|
696
639
|
if pks:
|
|
697
640
|
base_qs = model._base_manager.using(self.db)
|
|
698
|
-
print(f"Filter field: {filter_field}")
|
|
699
|
-
print(f"PKs to filter by: {pks}")
|
|
700
641
|
|
|
701
642
|
# Check if records exist
|
|
702
643
|
existing_count = base_qs.filter(**{f"{filter_field}__in": pks}).count()
|
|
703
|
-
print(f"Existing records with these PKs: {existing_count}")
|
|
704
644
|
|
|
705
645
|
if existing_count == 0:
|
|
706
|
-
print("WARNING: No existing records found with these PKs!")
|
|
707
646
|
continue
|
|
708
647
|
|
|
709
648
|
# Build CASE statements for each field to perform a single bulk update
|
|
@@ -712,7 +651,6 @@ class HookQuerySetMixin:
|
|
|
712
651
|
field = model._meta.get_field(field_name)
|
|
713
652
|
when_statements = []
|
|
714
653
|
|
|
715
|
-
print(f"Building CASE statement for field: {field_name}")
|
|
716
654
|
for pk, obj in zip(pks, batch):
|
|
717
655
|
# Check both pk and id attributes for the object
|
|
718
656
|
obj_pk = getattr(obj, 'pk', None)
|
|
@@ -722,26 +660,18 @@ class HookQuerySetMixin:
|
|
|
722
660
|
if obj_pk is None:
|
|
723
661
|
continue
|
|
724
662
|
value = getattr(obj, field_name)
|
|
725
|
-
print(f" PK {pk}: {field_name} = {value}")
|
|
726
663
|
when_statements.append(When(**{filter_field: pk}, then=Value(value, output_field=field)))
|
|
727
664
|
|
|
728
665
|
case_statements[field_name] = Case(*when_statements, output_field=field)
|
|
729
666
|
|
|
730
|
-
print(f"Case statements built: {list(case_statements.keys())}")
|
|
731
|
-
|
|
732
667
|
# Execute a single bulk update for all objects in this model
|
|
733
668
|
try:
|
|
734
669
|
updated_count = base_qs.filter(**{f"{filter_field}__in": pks}).update(**case_statements)
|
|
735
|
-
print(f"UPDATE QUERY EXECUTED - Updated {updated_count} rows")
|
|
736
670
|
total_updated += updated_count
|
|
737
671
|
except Exception as e:
|
|
738
|
-
print(f"ERROR during update: {e}")
|
|
739
672
|
import traceback
|
|
740
673
|
traceback.print_exc()
|
|
741
|
-
else:
|
|
742
|
-
print("No PKs found, skipping update")
|
|
743
674
|
|
|
744
|
-
print(f"Batch total updated: {total_updated}")
|
|
745
675
|
return total_updated
|
|
746
676
|
|
|
747
677
|
|
|
@@ -9,9 +9,9 @@ django_bulk_hooks/handler.py,sha256=xZt8iNdYF-ACz-MnKMY0co6scWINU5V5wC1lyDn844k,
|
|
|
9
9
|
django_bulk_hooks/manager.py,sha256=nfWiwU5-yAoxdnQsUMohxtyCpkV0MBv6X3wmipr9eQY,3697
|
|
10
10
|
django_bulk_hooks/models.py,sha256=7fnx5xd4HWXfLVlFhhiRzR92JRWFEuxgk6aSWLEsyJg,3996
|
|
11
11
|
django_bulk_hooks/priority.py,sha256=HG_2D35nga68lBCZmSXTcplXrjFoRgZFRDOy4ROKonY,376
|
|
12
|
-
django_bulk_hooks/queryset.py,sha256=
|
|
12
|
+
django_bulk_hooks/queryset.py,sha256=G8tzhFM8tirPXLJi0KwGWuybugboJoix21z7j_lPqJ4,27908
|
|
13
13
|
django_bulk_hooks/registry.py,sha256=-mQBizJ06nz_tajZBinViKx_uP2Tbc1tIpTEMv7lwKA,705
|
|
14
|
-
django_bulk_hooks-0.1.
|
|
15
|
-
django_bulk_hooks-0.1.
|
|
16
|
-
django_bulk_hooks-0.1.
|
|
17
|
-
django_bulk_hooks-0.1.
|
|
14
|
+
django_bulk_hooks-0.1.192.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
|
|
15
|
+
django_bulk_hooks-0.1.192.dist-info/METADATA,sha256=4QTA06jIRiiURXxuvwnQVLf6qTURJD48Zadn9PufPAk,7418
|
|
16
|
+
django_bulk_hooks-0.1.192.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
17
|
+
django_bulk_hooks-0.1.192.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|