django-bulk-hooks 0.1.214__py3-none-any.whl → 0.1.215__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/conditions.py +15 -1
- django_bulk_hooks/context.py +2 -1
- django_bulk_hooks/engine.py +18 -1
- django_bulk_hooks/queryset.py +14 -2
- django_bulk_hooks/registry.py +12 -1
- {django_bulk_hooks-0.1.214.dist-info → django_bulk_hooks-0.1.215.dist-info}/METADATA +3 -3
- django_bulk_hooks-0.1.215.dist-info/RECORD +17 -0
- {django_bulk_hooks-0.1.214.dist-info → django_bulk_hooks-0.1.215.dist-info}/WHEEL +1 -1
- django_bulk_hooks-0.1.214.dist-info/RECORD +0 -17
- {django_bulk_hooks-0.1.214.dist-info → django_bulk_hooks-0.1.215.dist-info}/LICENSE +0 -0
django_bulk_hooks/conditions.py
CHANGED
|
@@ -66,11 +66,25 @@ class HasChanged(HookCondition):
|
|
|
66
66
|
self.has_changed = has_changed
|
|
67
67
|
|
|
68
68
|
def check(self, instance, original_instance=None):
|
|
69
|
+
print(f"DEBUG: HasChanged.check called for field '{self.field}' on instance {getattr(instance, 'pk', 'No PK')}")
|
|
70
|
+
print(f"DEBUG: Original instance: {getattr(original_instance, 'pk', 'No PK') if original_instance else 'None'}")
|
|
71
|
+
|
|
69
72
|
if not original_instance:
|
|
73
|
+
print(f"DEBUG: No original instance, returning False")
|
|
70
74
|
return False
|
|
75
|
+
|
|
71
76
|
current = resolve_dotted_attr(instance, self.field)
|
|
72
77
|
previous = resolve_dotted_attr(original_instance, self.field)
|
|
73
|
-
|
|
78
|
+
|
|
79
|
+
# Add more detailed debugging
|
|
80
|
+
print(f"DEBUG: Field '{self.field}' - current value: {current} (type: {type(current)})")
|
|
81
|
+
print(f"DEBUG: Field '{self.field}' - previous value: {previous} (type: {type(previous)})")
|
|
82
|
+
print(f"DEBUG: Values are equal: {current == previous}")
|
|
83
|
+
|
|
84
|
+
result = (current != previous) == self.has_changed
|
|
85
|
+
print(f"DEBUG: HasChanged result: current={current}, previous={previous}, has_changed={self.has_changed}, result={result}")
|
|
86
|
+
|
|
87
|
+
return result
|
|
74
88
|
|
|
75
89
|
|
|
76
90
|
class WasEqual(HookCondition):
|
django_bulk_hooks/context.py
CHANGED
django_bulk_hooks/engine.py
CHANGED
|
@@ -29,6 +29,12 @@ def run(model_cls, event, new_records, old_records=None, ctx=None):
|
|
|
29
29
|
print(f"DEBUG: Call stack (last 3 frames):")
|
|
30
30
|
for line in stack[-4:-1]: # Show last 3 frames before this one
|
|
31
31
|
print(f" {line.strip()}")
|
|
32
|
+
print(f"DEBUG: Total hooks found: {len(hooks)}")
|
|
33
|
+
|
|
34
|
+
# Check if we're in a bypass context
|
|
35
|
+
if ctx and hasattr(ctx, 'bypass_hooks') and ctx.bypass_hooks:
|
|
36
|
+
print(f"DEBUG: Context has bypass_hooks=True, skipping hook execution")
|
|
37
|
+
return
|
|
32
38
|
|
|
33
39
|
# For BEFORE_* events, run model.clean() first for validation
|
|
34
40
|
if event.startswith("before_"):
|
|
@@ -41,6 +47,7 @@ def run(model_cls, event, new_records, old_records=None, ctx=None):
|
|
|
41
47
|
|
|
42
48
|
# Process hooks
|
|
43
49
|
for handler_cls, method_name, condition, priority in hooks:
|
|
50
|
+
print(f"DEBUG: Processing hook {handler_cls.__name__}.{method_name} with condition: {condition}")
|
|
44
51
|
handler_instance = handler_cls()
|
|
45
52
|
func = getattr(handler_instance, method_name)
|
|
46
53
|
|
|
@@ -52,9 +59,16 @@ def run(model_cls, event, new_records, old_records=None, ctx=None):
|
|
|
52
59
|
old_records or [None] * len(new_records),
|
|
53
60
|
strict=True,
|
|
54
61
|
):
|
|
55
|
-
if not condition
|
|
62
|
+
if not condition:
|
|
63
|
+
print(f"DEBUG: No condition, adding record {new.pk if hasattr(new, 'pk') else 'No PK'}")
|
|
56
64
|
to_process_new.append(new)
|
|
57
65
|
to_process_old.append(original)
|
|
66
|
+
else:
|
|
67
|
+
condition_result = condition.check(new, original)
|
|
68
|
+
print(f"DEBUG: Condition {condition.__class__.__name__} check result: {condition_result} for record {new.pk if hasattr(new, 'pk') else 'No PK'}")
|
|
69
|
+
if condition_result:
|
|
70
|
+
to_process_new.append(new)
|
|
71
|
+
to_process_old.append(original)
|
|
58
72
|
|
|
59
73
|
if to_process_new:
|
|
60
74
|
print(
|
|
@@ -66,4 +80,7 @@ def run(model_cls, event, new_records, old_records=None, ctx=None):
|
|
|
66
80
|
old_records=to_process_old if any(to_process_old) else None,
|
|
67
81
|
)
|
|
68
82
|
except Exception as e:
|
|
83
|
+
print(f"DEBUG: Hook execution failed: {e}")
|
|
69
84
|
raise
|
|
85
|
+
else:
|
|
86
|
+
print(f"DEBUG: No records to process for hook {handler_cls.__name__}.{method_name}")
|
django_bulk_hooks/queryset.py
CHANGED
|
@@ -161,10 +161,12 @@ class HookQuerySetMixin:
|
|
|
161
161
|
|
|
162
162
|
# Fire hooks before DB ops
|
|
163
163
|
if not bypass_hooks:
|
|
164
|
-
ctx = HookContext(model_cls)
|
|
164
|
+
ctx = HookContext(model_cls, bypass_hooks=False)
|
|
165
165
|
if not bypass_validation:
|
|
166
166
|
engine.run(model_cls, VALIDATE_CREATE, objs, ctx=ctx)
|
|
167
167
|
engine.run(model_cls, BEFORE_CREATE, objs, ctx=ctx)
|
|
168
|
+
else:
|
|
169
|
+
ctx = HookContext(model_cls, bypass_hooks=True)
|
|
168
170
|
|
|
169
171
|
# For MTI models, we need to handle them specially
|
|
170
172
|
if is_mti:
|
|
@@ -219,6 +221,10 @@ class HookQuerySetMixin:
|
|
|
219
221
|
f"bulk_update expected instances of {model_cls.__name__}, but got {set(type(obj).__name__ for obj in objs)}"
|
|
220
222
|
)
|
|
221
223
|
|
|
224
|
+
print(f"DEBUG: bulk_update called with bypass_hooks={bypass_hooks} (type: {type(bypass_hooks)}), bypass_validation={bypass_validation}")
|
|
225
|
+
print(f"DEBUG: bulk_update for model {model_cls.__name__} with {len(objs)} objects")
|
|
226
|
+
print(f"DEBUG: kwargs: {kwargs}")
|
|
227
|
+
|
|
222
228
|
# Check for MTI
|
|
223
229
|
is_mti = False
|
|
224
230
|
for parent in model_cls._meta.all_parents:
|
|
@@ -237,7 +243,7 @@ class HookQuerySetMixin:
|
|
|
237
243
|
}
|
|
238
244
|
originals = [original_map.get(obj.pk) for obj in objs]
|
|
239
245
|
|
|
240
|
-
ctx = HookContext(model_cls)
|
|
246
|
+
ctx = HookContext(model_cls, bypass_hooks=False)
|
|
241
247
|
|
|
242
248
|
# Run validation hooks first
|
|
243
249
|
if not bypass_validation:
|
|
@@ -254,6 +260,7 @@ class HookQuerySetMixin:
|
|
|
254
260
|
fields = list(fields_set)
|
|
255
261
|
else:
|
|
256
262
|
print(f"DEBUG: bypass_hooks=True, skipping hooks for {len(objs)} objects")
|
|
263
|
+
ctx = HookContext(model_cls, bypass_hooks=True)
|
|
257
264
|
|
|
258
265
|
# Handle auto_now fields like Django's update_or_create does
|
|
259
266
|
fields_set = set(fields)
|
|
@@ -278,7 +285,12 @@ class HookQuerySetMixin:
|
|
|
278
285
|
for k, v in kwargs.items()
|
|
279
286
|
if k not in ["bypass_hooks", "bypass_validation"]
|
|
280
287
|
}
|
|
288
|
+
print(f"DEBUG: Calling Django's bulk_update with kwargs: {django_kwargs}")
|
|
289
|
+
# Call Django's bulk_update with hook suspension to prevent double execution
|
|
290
|
+
# Django's bulk_update internally calls .update() which would trigger our hooks again
|
|
291
|
+
print(f"DEBUG: About to call Django's bulk_update")
|
|
281
292
|
result = super().bulk_update(objs, fields, **django_kwargs)
|
|
293
|
+
print(f"DEBUG: Django's bulk_update completed, result: {result}")
|
|
282
294
|
|
|
283
295
|
if not bypass_hooks:
|
|
284
296
|
print(
|
django_bulk_hooks/registry.py
CHANGED
|
@@ -14,10 +14,21 @@ def register_hook(
|
|
|
14
14
|
hooks.append((handler_cls, method_name, condition, priority))
|
|
15
15
|
# keep sorted by priority
|
|
16
16
|
hooks.sort(key=lambda x: x[3])
|
|
17
|
+
print(f"DEBUG: Registered hook {handler_cls.__name__}.{method_name} for {model.__name__}.{event} with condition: {condition}")
|
|
18
|
+
print(f"DEBUG: Model class: {model} (id: {id(model)})")
|
|
19
|
+
print(f"DEBUG: Total hooks for {model.__name__}.{event}: {len(hooks)}")
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
def get_hooks(model, event):
|
|
20
|
-
|
|
23
|
+
key = (model, event)
|
|
24
|
+
hooks = _hooks.get(key, [])
|
|
25
|
+
print(f"DEBUG: get_hooks called for {model.__name__}.{event}, found {len(hooks)} hooks")
|
|
26
|
+
print(f"DEBUG: Hook key: {key}")
|
|
27
|
+
print(f"DEBUG: Model class: {model} (id: {id(model)})")
|
|
28
|
+
print(f"DEBUG: All registered hook keys: {list(_hooks.keys())}")
|
|
29
|
+
for hook in hooks:
|
|
30
|
+
handler_cls, method_name, condition, priority = hook
|
|
31
|
+
print(f"DEBUG: Hook: {handler_cls.__name__}.{method_name} with condition: {condition}")
|
|
21
32
|
return hooks
|
|
22
33
|
|
|
23
34
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: django-bulk-hooks
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.215
|
|
4
4
|
Summary: Hook-style hooks for Django bulk operations like bulk_create and bulk_update.
|
|
5
|
-
Home-page: https://github.com/AugendLimited/django-bulk-hooks
|
|
6
5
|
License: MIT
|
|
7
6
|
Keywords: django,bulk,hooks
|
|
8
7
|
Author: Konrad Beck
|
|
@@ -14,6 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
15
|
Requires-Dist: Django (>=4.0)
|
|
16
|
+
Project-URL: Homepage, https://github.com/AugendLimited/django-bulk-hooks
|
|
17
17
|
Project-URL: Repository, https://github.com/AugendLimited/django-bulk-hooks
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
django_bulk_hooks/__init__.py,sha256=uUgpnb9AWjIAcWNpCMqBcOewSnpJjJYH6cjPbQkzoNU,140
|
|
2
|
+
django_bulk_hooks/conditions.py,sha256=0NEAtiIxS9DI4DcqvqGPaCJJR-5ldHqY9uQ9VuM2YYc,6865
|
|
3
|
+
django_bulk_hooks/constants.py,sha256=3x1H1fSUUNo0DZONN7GUVDuySZctTR-jtByBHmAIX5w,303
|
|
4
|
+
django_bulk_hooks/context.py,sha256=47T9FivluZjhH45kZOoPJC2HLyozRFcL1Sqk4LjJheY,1113
|
|
5
|
+
django_bulk_hooks/decorators.py,sha256=WD7Jn7QAvY8F4wOsYlIpjoM9-FdHXSKB7hH9ot-lkYQ,4896
|
|
6
|
+
django_bulk_hooks/engine.py,sha256=pZGN3-O7SRZeMq69DVjtAAU7CQzcm8sj8GZyTUctBdc,3140
|
|
7
|
+
django_bulk_hooks/enums.py,sha256=Zo8_tJzuzZ2IKfVc7gZ-0tWPT8q1QhqZbAyoh9ZVJbs,381
|
|
8
|
+
django_bulk_hooks/handler.py,sha256=xZt8iNdYF-ACz-MnKMY0co6scWINU5V5wC1lyDn844k,4854
|
|
9
|
+
django_bulk_hooks/manager.py,sha256=nfWiwU5-yAoxdnQsUMohxtyCpkV0MBv6X3wmipr9eQY,3697
|
|
10
|
+
django_bulk_hooks/models.py,sha256=TA2dBIA1nJBiYt6joefWkpFIQZWysF9kZlkBYvEe59c,4358
|
|
11
|
+
django_bulk_hooks/priority.py,sha256=HG_2D35nga68lBCZmSXTcplXrjFoRgZFRDOy4ROKonY,376
|
|
12
|
+
django_bulk_hooks/queryset.py,sha256=B7kJWRxmMpg40Q0hvwosxYC_1UXxs82SM_U1Il74nrY,32824
|
|
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,,
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
django_bulk_hooks/__init__.py,sha256=uUgpnb9AWjIAcWNpCMqBcOewSnpJjJYH6cjPbQkzoNU,140
|
|
2
|
-
django_bulk_hooks/conditions.py,sha256=mTvlLcttixbXRkTSNZU5VewkPUavbXRuD2BkJbVWMkw,6041
|
|
3
|
-
django_bulk_hooks/constants.py,sha256=3x1H1fSUUNo0DZONN7GUVDuySZctTR-jtByBHmAIX5w,303
|
|
4
|
-
django_bulk_hooks/context.py,sha256=4IPuOX8TBAYBEMzN0RNHWgE6Giy2ZnR5uRXfd1cpIwk,1051
|
|
5
|
-
django_bulk_hooks/decorators.py,sha256=WD7Jn7QAvY8F4wOsYlIpjoM9-FdHXSKB7hH9ot-lkYQ,4896
|
|
6
|
-
django_bulk_hooks/engine.py,sha256=aoeGCW9dne_5qB4-0YpndC3vnLGlLOYGwyWjmbFbZvg,2133
|
|
7
|
-
django_bulk_hooks/enums.py,sha256=Zo8_tJzuzZ2IKfVc7gZ-0tWPT8q1QhqZbAyoh9ZVJbs,381
|
|
8
|
-
django_bulk_hooks/handler.py,sha256=xZt8iNdYF-ACz-MnKMY0co6scWINU5V5wC1lyDn844k,4854
|
|
9
|
-
django_bulk_hooks/manager.py,sha256=nfWiwU5-yAoxdnQsUMohxtyCpkV0MBv6X3wmipr9eQY,3697
|
|
10
|
-
django_bulk_hooks/models.py,sha256=TA2dBIA1nJBiYt6joefWkpFIQZWysF9kZlkBYvEe59c,4358
|
|
11
|
-
django_bulk_hooks/priority.py,sha256=HG_2D35nga68lBCZmSXTcplXrjFoRgZFRDOy4ROKonY,376
|
|
12
|
-
django_bulk_hooks/queryset.py,sha256=AK4znACMv5tyZyFmPchreO8yn9xDERIkmerfiuSRURs,31941
|
|
13
|
-
django_bulk_hooks/registry.py,sha256=-mQBizJ06nz_tajZBinViKx_uP2Tbc1tIpTEMv7lwKA,705
|
|
14
|
-
django_bulk_hooks-0.1.214.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
|
|
15
|
-
django_bulk_hooks-0.1.214.dist-info/METADATA,sha256=S1UR9Sm-y6xTmf2Yi-QAIKwmt2p-dmqsJgJcrvPp2BE,9049
|
|
16
|
-
django_bulk_hooks-0.1.214.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
17
|
-
django_bulk_hooks-0.1.214.dist-info/RECORD,,
|
|
File without changes
|