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

@@ -12,10 +12,22 @@ def get_hook_queue():
12
12
  return _hook_context.queue
13
13
 
14
14
 
15
+ def set_bypass_hooks(bypass_hooks):
16
+ """Set the current bypass_hooks state for the current thread."""
17
+ _hook_context.bypass_hooks = bypass_hooks
18
+
19
+
20
+ def get_bypass_hooks():
21
+ """Get the current bypass_hooks state for the current thread."""
22
+ return getattr(_hook_context, 'bypass_hooks', False)
23
+
24
+
15
25
  class HookContext:
16
26
  def __init__(self, model, bypass_hooks=False):
17
27
  self.model = model
18
28
  self.bypass_hooks = bypass_hooks
29
+ # Set the thread-local bypass state when creating a context
30
+ set_bypass_hooks(bypass_hooks)
19
31
 
20
32
  @property
21
33
  def is_executing(self):
@@ -72,9 +72,19 @@ class HookQuerySetMixin:
72
72
  for field, value in kwargs.items():
73
73
  setattr(obj, field, value)
74
74
 
75
- # Run BEFORE_UPDATE hooks
76
- ctx = HookContext(model_cls)
77
- engine.run(model_cls, BEFORE_UPDATE, instances, originals, ctx=ctx)
75
+ # Check if we're in a bulk operation context to prevent double hook execution
76
+ from django_bulk_hooks.context import get_bypass_hooks
77
+ current_bypass_hooks = get_bypass_hooks()
78
+
79
+ # If we're in a bulk operation context, skip hooks to prevent double execution
80
+ if current_bypass_hooks:
81
+ print(f"DEBUG: update method skipping hooks due to bulk operation context")
82
+ ctx = HookContext(model_cls, bypass_hooks=True)
83
+ else:
84
+ print(f"DEBUG: update method running hooks (standalone update)")
85
+ ctx = HookContext(model_cls, bypass_hooks=False)
86
+ # Run BEFORE_UPDATE hooks only for standalone updates
87
+ engine.run(model_cls, BEFORE_UPDATE, instances, originals, ctx=ctx)
78
88
 
79
89
  # Use Django's built-in update logic directly
80
90
  # Call the base QuerySet implementation to avoid recursion
@@ -101,8 +111,12 @@ class HookQuerySetMixin:
101
111
  getattr(refreshed_instance, field.name),
102
112
  )
103
113
 
104
- # Run AFTER_UPDATE hooks
105
- engine.run(model_cls, AFTER_UPDATE, instances, originals, ctx=ctx)
114
+ # Run AFTER_UPDATE hooks only for standalone updates
115
+ if not current_bypass_hooks:
116
+ print(f"DEBUG: update method running AFTER_UPDATE hooks")
117
+ engine.run(model_cls, AFTER_UPDATE, instances, originals, ctx=ctx)
118
+ else:
119
+ print(f"DEBUG: update method skipping AFTER_UPDATE hooks due to bulk operation context")
106
120
 
107
121
  return update_count
108
122
 
@@ -161,12 +175,13 @@ class HookQuerySetMixin:
161
175
 
162
176
  # Fire hooks before DB ops
163
177
  if not bypass_hooks:
164
- ctx = HookContext(model_cls, bypass_hooks=False)
178
+ ctx = HookContext(model_cls, bypass_hooks=False) # Pass bypass_hooks
165
179
  if not bypass_validation:
166
180
  engine.run(model_cls, VALIDATE_CREATE, objs, ctx=ctx)
167
181
  engine.run(model_cls, BEFORE_CREATE, objs, ctx=ctx)
168
182
  else:
169
- ctx = HookContext(model_cls, bypass_hooks=True)
183
+ ctx = HookContext(model_cls, bypass_hooks=True) # Pass bypass_hooks
184
+ print(f"DEBUG: Set thread-local bypass_hooks=True for nested calls in bulk_create")
170
185
 
171
186
  # For MTI models, we need to handle them specially
172
187
  if is_mti:
@@ -233,8 +248,7 @@ class HookQuerySetMixin:
233
248
  break
234
249
 
235
250
  if not bypass_hooks:
236
- print(f"DEBUG: bypass_hooks=False, running hooks for {len(objs)} objects")
237
- # Load originals for hook comparison
251
+ print(f"DEBUG: bulk_update running hooks for {len(objs)} objects")
238
252
  original_map = {
239
253
  obj.pk: obj
240
254
  for obj in model_cls._base_manager.filter(
@@ -242,12 +256,9 @@ class HookQuerySetMixin:
242
256
  )
243
257
  }
244
258
  originals = [original_map.get(obj.pk) for obj in objs]
245
-
246
259
  ctx = HookContext(model_cls, bypass_hooks=False)
247
-
248
260
  # Run validation hooks first
249
- if not bypass_validation:
250
- engine.run(model_cls, VALIDATE_UPDATE, objs, originals, ctx=ctx)
261
+ engine.run(model_cls, VALIDATE_UPDATE, objs, originals, ctx=ctx)
251
262
 
252
263
  # Then run business logic hooks
253
264
  engine.run(model_cls, BEFORE_UPDATE, objs, originals, ctx=ctx)
@@ -259,8 +270,10 @@ class HookQuerySetMixin:
259
270
  fields_set.update(modified_fields)
260
271
  fields = list(fields_set)
261
272
  else:
262
- print(f"DEBUG: bypass_hooks=True, skipping hooks for {len(objs)} objects")
273
+ print(f"DEBUG: bulk_update skipping hooks and setting bulk context to prevent double execution")
263
274
  ctx = HookContext(model_cls, bypass_hooks=True)
275
+ print(f"DEBUG: Set thread-local bypass_hooks=True to prevent nested update() calls from running hooks")
276
+ originals = [None] * len(objs) # Ensure originals is defined for after_update call
264
277
 
265
278
  # Handle auto_now fields like Django's update_or_create does
266
279
  fields_set = set(fields)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: django-bulk-hooks
3
- Version: 0.1.215
3
+ Version: 0.1.217
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
@@ -1,7 +1,7 @@
1
1
  django_bulk_hooks/__init__.py,sha256=uUgpnb9AWjIAcWNpCMqBcOewSnpJjJYH6cjPbQkzoNU,140
2
2
  django_bulk_hooks/conditions.py,sha256=0NEAtiIxS9DI4DcqvqGPaCJJR-5ldHqY9uQ9VuM2YYc,6865
3
3
  django_bulk_hooks/constants.py,sha256=3x1H1fSUUNo0DZONN7GUVDuySZctTR-jtByBHmAIX5w,303
4
- django_bulk_hooks/context.py,sha256=47T9FivluZjhH45kZOoPJC2HLyozRFcL1Sqk4LjJheY,1113
4
+ django_bulk_hooks/context.py,sha256=_NbGWTq9s66g0vbFIaqN4GlIHWQmFg3EQ44qY8YvvEg,1537
5
5
  django_bulk_hooks/decorators.py,sha256=WD7Jn7QAvY8F4wOsYlIpjoM9-FdHXSKB7hH9ot-lkYQ,4896
6
6
  django_bulk_hooks/engine.py,sha256=pZGN3-O7SRZeMq69DVjtAAU7CQzcm8sj8GZyTUctBdc,3140
7
7
  django_bulk_hooks/enums.py,sha256=Zo8_tJzuzZ2IKfVc7gZ-0tWPT8q1QhqZbAyoh9ZVJbs,381
@@ -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=TA2dBIA1nJBiYt6joefWkpFIQZWysF9kZlkBYvEe59c,4358
11
11
  django_bulk_hooks/priority.py,sha256=HG_2D35nga68lBCZmSXTcplXrjFoRgZFRDOy4ROKonY,376
12
- django_bulk_hooks/queryset.py,sha256=B7kJWRxmMpg40Q0hvwosxYC_1UXxs82SM_U1Il74nrY,32824
12
+ django_bulk_hooks/queryset.py,sha256=hvi22HhnIpbZunSjdLgfBvkl_7JrIudMufDd2jKvS1c,33987
13
13
  django_bulk_hooks/registry.py,sha256=fbr6T9MidCs0oV6LhocLIVo3TGs2EazGTVqapoUbm2U,1436
14
- django_bulk_hooks-0.1.215.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
15
- django_bulk_hooks-0.1.215.dist-info/METADATA,sha256=qAPe-zyNl6Ia1AXLJ0BOmLI20ug9elZyt_P4557VTeI,9061
16
- django_bulk_hooks-0.1.215.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
17
- django_bulk_hooks-0.1.215.dist-info/RECORD,,
14
+ django_bulk_hooks-0.1.217.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
15
+ django_bulk_hooks-0.1.217.dist-info/METADATA,sha256=Ae7ndlaxYXGMLgo3Waincm0GAHwBh9Wjul7suGDiqVo,9061
16
+ django_bulk_hooks-0.1.217.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
17
+ django_bulk_hooks-0.1.217.dist-info/RECORD,,