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

@@ -24,9 +24,23 @@ class HookQuerySet(models.QuerySet):
24
24
  objs = list(self)
25
25
  if not objs:
26
26
  return 0
27
- # Use our bulk_delete method to handle hooks properly
28
- self.bulk_delete(objs)
29
- return len(objs)
27
+
28
+ model_cls = self.model
29
+ ctx = HookContext(model_cls)
30
+
31
+ # Run validation hooks first
32
+ engine.run(model_cls, VALIDATE_DELETE, objs, ctx=ctx)
33
+
34
+ # Then run business logic hooks
35
+ engine.run(model_cls, BEFORE_DELETE, objs, ctx=ctx)
36
+
37
+ # Use Django's standard delete() method
38
+ result = super().delete()
39
+
40
+ # Run AFTER_DELETE hooks
41
+ engine.run(model_cls, AFTER_DELETE, objs, ctx=ctx)
42
+
43
+ return result
30
44
 
31
45
  @transaction.atomic
32
46
  def update(self, **kwargs):
@@ -34,28 +48,33 @@ class HookQuerySet(models.QuerySet):
34
48
  if not instances:
35
49
  return 0
36
50
 
51
+ model_cls = self.model
52
+ pks = [obj.pk for obj in instances]
53
+
54
+ # Load originals for hook comparison and ensure they match the order of instances
55
+ # Use the base manager to avoid recursion
56
+ original_map = {
57
+ obj.pk: obj for obj in model_cls._base_manager.filter(pk__in=pks)
58
+ }
59
+ originals = [original_map.get(obj.pk) for obj in instances]
60
+
37
61
  # Apply field updates to instances
38
62
  for obj in instances:
39
63
  for field, value in kwargs.items():
40
64
  setattr(obj, field, value)
41
65
 
42
- # Use our bulk_update method to handle hooks properly
43
- self.bulk_update(instances, list(kwargs.keys()))
44
- return len(instances)
66
+ # Run BEFORE_UPDATE hooks
67
+ ctx = HookContext(model_cls)
68
+ engine.run(model_cls, BEFORE_UPDATE, instances, originals, ctx=ctx)
45
69
 
46
- def save(self, obj):
47
- """
48
- Save a single object using the appropriate bulk operation.
49
- """
50
- if obj.pk:
51
- # Use bulk_update for existing objects
52
- self.bulk_update(
53
- [obj], [field.name for field in obj._meta.fields if field.name != "id"]
54
- )
55
- else:
56
- # Use bulk_create for new objects
57
- self.bulk_create([obj])
58
- return obj
70
+ # Use Django's built-in update logic directly
71
+ # Call the base QuerySet implementation to avoid recursion
72
+ update_count = super().update(**kwargs)
73
+
74
+ # Run AFTER_UPDATE hooks
75
+ engine.run(model_cls, AFTER_UPDATE, instances, originals, ctx=ctx)
76
+
77
+ return update_count
59
78
 
60
79
  @transaction.atomic
61
80
  def bulk_create(
@@ -139,17 +158,21 @@ class HookQuerySet(models.QuerySet):
139
158
  )
140
159
  else:
141
160
  # For single-table models, use Django's built-in bulk_create
161
+ # but we need to call it on the base manager to avoid recursion
142
162
  # Filter out custom parameters that Django's bulk_create doesn't accept
143
- django_kwargs = {
144
- "batch_size": batch_size,
145
- "ignore_conflicts": ignore_conflicts,
146
- "update_conflicts": update_conflicts,
147
- "update_fields": update_fields,
148
- "unique_fields": unique_fields,
149
- }
150
- # Remove custom hook kwargs if present
151
- django_kwargs = {k: v for k, v in django_kwargs.items() if v is not None}
152
- result = super().bulk_create(objs, **django_kwargs)
163
+
164
+ # Use Django's original QuerySet to avoid recursive calls
165
+ from django.db.models import QuerySet
166
+
167
+ original_qs = QuerySet(model_cls, using=self.db)
168
+ result = original_qs.bulk_create(
169
+ objs,
170
+ batch_size=batch_size,
171
+ ignore_conflicts=ignore_conflicts,
172
+ update_conflicts=update_conflicts,
173
+ update_fields=update_fields,
174
+ unique_fields=unique_fields,
175
+ )
153
176
 
154
177
  # Fire AFTER_CREATE hooks
155
178
  if not bypass_hooks:
@@ -220,41 +243,6 @@ class HookQuerySet(models.QuerySet):
220
243
 
221
244
  return objs
222
245
 
223
- @transaction.atomic
224
- def bulk_delete(
225
- self, objs, batch_size=None, bypass_hooks=False, bypass_validation=False
226
- ):
227
- if not objs:
228
- return []
229
-
230
- model_cls = self.model
231
-
232
- if any(not isinstance(obj, model_cls) for obj in objs):
233
- raise TypeError(
234
- f"bulk_delete expected instances of {model_cls.__name__}, but got {set(type(obj).__name__ for obj in objs)}"
235
- )
236
-
237
- ctx = HookContext(model_cls)
238
-
239
- if not bypass_hooks:
240
- # Run validation hooks first
241
- if not bypass_validation:
242
- engine.run(model_cls, VALIDATE_DELETE, objs, ctx=ctx)
243
-
244
- # Then run business logic hooks
245
- engine.run(model_cls, BEFORE_DELETE, objs, ctx=ctx)
246
-
247
- pks = [obj.pk for obj in objs if obj.pk is not None]
248
-
249
- # Call the base QuerySet implementation to avoid recursion
250
- # The hooks have already been fired above, so we don't need them again
251
- super().bulk_delete(objs, batch_size=batch_size)
252
-
253
- if not bypass_hooks:
254
- engine.run(model_cls, AFTER_DELETE, objs, ctx=ctx)
255
-
256
- return objs
257
-
258
246
  def _detect_modified_fields(self, new_instances, original_instances):
259
247
  """
260
248
  Detect fields that were modified during BEFORE_UPDATE hooks by comparing
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-bulk-hooks
3
- Version: 0.1.172
3
+ Version: 0.1.175
4
4
  Summary: Hook-style hooks for Django bulk operations like bulk_create and bulk_update.
5
5
  Home-page: https://github.com/AugendLimited/django-bulk-hooks
6
6
  License: MIT
@@ -9,9 +9,9 @@ django_bulk_hooks/handler.py,sha256=xZt8iNdYF-ACz-MnKMY0co6scWINU5V5wC1lyDn844k,
9
9
  django_bulk_hooks/manager.py,sha256=OSzW8eVzknLV1WCvZcBkWMz9x_Vjq4bJM8raVXKiZvI,5085
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=yGzVFWWbg7mjJxH9Gx1hXw9Mf82H0XmMlfKZn47WMJw,23222
12
+ django_bulk_hooks/queryset.py,sha256=wP1PHzDJ-n_F6RtPzQUdB2j16aALabDl0gbaMJAE2eI,22812
13
13
  django_bulk_hooks/registry.py,sha256=-mQBizJ06nz_tajZBinViKx_uP2Tbc1tIpTEMv7lwKA,705
14
- django_bulk_hooks-0.1.172.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
15
- django_bulk_hooks-0.1.172.dist-info/METADATA,sha256=JQDexi4jxTyskLLwCDmRemDvHPeihDdkNZOJSohsLjk,6939
16
- django_bulk_hooks-0.1.172.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
17
- django_bulk_hooks-0.1.172.dist-info/RECORD,,
14
+ django_bulk_hooks-0.1.175.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
15
+ django_bulk_hooks-0.1.175.dist-info/METADATA,sha256=HmgU2xtMNjhwLejwg5ehchMkJPSYn6B_JRcRmn3EoXs,6939
16
+ django_bulk_hooks-0.1.175.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
17
+ django_bulk_hooks-0.1.175.dist-info/RECORD,,