django-bulk-hooks 0.2.58__py3-none-any.whl → 0.2.59__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.

@@ -740,6 +740,8 @@ class BulkOperationCoordinator:
740
740
  if not result_objects:
741
741
  return
742
742
 
743
+ # First pass: collect objects with metadata and objects needing timestamp check
744
+ objects_needing_timestamp_check = []
743
745
  for obj in result_objects:
744
746
  # Check if metadata was set
745
747
  if hasattr(obj, "_bulk_hooks_was_created"):
@@ -749,29 +751,52 @@ class BulkOperationCoordinator:
749
751
  else:
750
752
  updated_objects.append(obj)
751
753
  else:
752
- # Fallback: if no metadata, check timestamps
754
+ # Need to check timestamps - collect for bulk query
755
+ objects_needing_timestamp_check.append(obj)
756
+
757
+ # Bulk fetch timestamps for objects without metadata (avoids N+1 queries)
758
+ if objects_needing_timestamp_check:
759
+ # Group by model class to handle MTI scenarios
760
+ objects_by_model = {}
761
+ for obj in objects_needing_timestamp_check:
753
762
  model_cls = obj.__class__
763
+ if model_cls not in objects_by_model:
764
+ objects_by_model[model_cls] = []
765
+ objects_by_model[model_cls].append(obj)
766
+
767
+ # Fetch timestamps in bulk for each model class
768
+ for model_cls, objs in objects_by_model.items():
754
769
  if hasattr(model_cls, "created_at") and hasattr(model_cls, "updated_at"):
755
- # Reload from DB to get accurate timestamps
756
- db_obj = model_cls.objects.filter(pk=obj.pk).values("created_at", "updated_at").first()
757
- if db_obj:
758
- created_at = db_obj["created_at"]
759
- updated_at = db_obj["updated_at"]
760
- if created_at and updated_at:
761
- time_diff = abs((updated_at - created_at).total_seconds())
762
- if time_diff <= 1.0: # Within 1 second = just created
763
- created_objects.append(obj)
770
+ # Bulk fetch timestamps for all objects of this model
771
+ pks = [obj.pk for obj in objs if obj.pk is not None]
772
+ if pks:
773
+ timestamp_map = {
774
+ record["pk"]: (record["created_at"], record["updated_at"])
775
+ for record in model_cls.objects.filter(pk__in=pks).values("pk", "created_at", "updated_at")
776
+ }
777
+
778
+ # Classify each object based on timestamps
779
+ for obj in objs:
780
+ if obj.pk in timestamp_map:
781
+ created_at, updated_at = timestamp_map[obj.pk]
782
+ if created_at and updated_at:
783
+ time_diff = abs((updated_at - created_at).total_seconds())
784
+ if time_diff <= 1.0: # Within 1 second = just created
785
+ created_objects.append(obj)
786
+ else:
787
+ updated_objects.append(obj)
788
+ else:
789
+ # No timestamps, default to created
790
+ created_objects.append(obj)
764
791
  else:
765
- updated_objects.append(obj)
766
- else:
767
- # No timestamps, default to created
768
- created_objects.append(obj)
792
+ # Object not found, treat as created
793
+ created_objects.append(obj)
769
794
  else:
770
- # Object not found, treat as created
771
- created_objects.append(obj)
795
+ # No PKs, default all to created
796
+ created_objects.extend(objs)
772
797
  else:
773
798
  # No timestamp fields, default to created
774
- created_objects.append(obj)
799
+ created_objects.extend(objs)
775
800
 
776
801
  logger.info(f"Upsert after hooks: {len(created_objects)} created, {len(updated_objects)} updated")
777
802
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: django-bulk-hooks
3
- Version: 0.2.58
3
+ Version: 0.2.59
4
4
  Summary: Hook-style hooks for Django bulk operations like bulk_create and bulk_update.
5
5
  License: MIT
6
6
  Keywords: django,bulk,hooks
@@ -14,14 +14,14 @@ django_bulk_hooks/models.py,sha256=4Vvi2LiGP0g4j08a5liqBROfsO8Wd_ermBoyjKwfrPU,2
14
14
  django_bulk_hooks/operations/__init__.py,sha256=BtJYjmRhe_sScivLsniDaZmBkm0ZLvcmzXFKL7QY2Xg,550
15
15
  django_bulk_hooks/operations/analyzer.py,sha256=wAG8sAG9NwfwNqG9z81VfGR7AANDzRmMGE_o82MWji4,10689
16
16
  django_bulk_hooks/operations/bulk_executor.py,sha256=Y-wkvuV_X-SZmI965JVrrtwbzPZVggUfy8mR1pzP9d0,27048
17
- django_bulk_hooks/operations/coordinator.py,sha256=iGavJLqe3eYRqFay8cMn6muwyRYzQo-HFGphsS5hL6g,30799
17
+ django_bulk_hooks/operations/coordinator.py,sha256=1Ka5eZJXTFjx3tr-BD6Tr350Y2T57SUOX3vjagBYBvM,32193
18
18
  django_bulk_hooks/operations/field_utils.py,sha256=Tvr5bcZLG8imH-r2S85oui1Cbw6hGv3VtuIMn4OvsU4,2895
19
19
  django_bulk_hooks/operations/mti_handler.py,sha256=173jghcxCE5UEZxM1QJRS-lWg0-KJxCQCbWHVKppIEM,26000
20
20
  django_bulk_hooks/operations/mti_plans.py,sha256=7STQ2oA2ZT8cEG3-t-6xciRAdf7OeSf0gRLXR_BRG-Q,3363
21
21
  django_bulk_hooks/operations/record_classifier.py,sha256=kqML4aO11X9K3SSJ5DUlUukwI172j_Tk12Kr77ee8q8,7065
22
22
  django_bulk_hooks/queryset.py,sha256=aQitlbexcVnmeAdc0jtO3hci39p4QEu4srQPEzozy5s,5546
23
23
  django_bulk_hooks/registry.py,sha256=uum5jhGI3TPaoiXuA1MdBdu4gbE3rQGGwQ5YDjiMcjk,7949
24
- django_bulk_hooks-0.2.58.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
25
- django_bulk_hooks-0.2.58.dist-info/METADATA,sha256=kVna-_dN9xVNaMMZHZUzm-Ab4IjhVzA1L8XXPms5T7o,9265
26
- django_bulk_hooks-0.2.58.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
27
- django_bulk_hooks-0.2.58.dist-info/RECORD,,
24
+ django_bulk_hooks-0.2.59.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
25
+ django_bulk_hooks-0.2.59.dist-info/METADATA,sha256=Zqy1xIlJ4pSLl-rxnjA96tNhdgomhT21cnHI7Z9ZbE8,9265
26
+ django_bulk_hooks-0.2.59.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
27
+ django_bulk_hooks-0.2.59.dist-info/RECORD,,