django-bulk-hooks 0.1.219__py3-none-any.whl → 0.1.221__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 +8 -6
- django_bulk_hooks/models.py +6 -7
- django_bulk_hooks/queryset.py +8 -8
- django_bulk_hooks/registry.py +6 -1
- {django_bulk_hooks-0.1.219.dist-info → django_bulk_hooks-0.1.221.dist-info}/METADATA +1 -1
- {django_bulk_hooks-0.1.219.dist-info → django_bulk_hooks-0.1.221.dist-info}/RECORD +8 -8
- {django_bulk_hooks-0.1.219.dist-info → django_bulk_hooks-0.1.221.dist-info}/LICENSE +0 -0
- {django_bulk_hooks-0.1.219.dist-info → django_bulk_hooks-0.1.221.dist-info}/WHEEL +0 -0
django_bulk_hooks/conditions.py
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
logger = logging.getLogger(__name__)
|
|
4
|
+
|
|
5
|
+
|
|
1
6
|
def resolve_dotted_attr(instance, dotted_path):
|
|
2
7
|
"""
|
|
3
8
|
Recursively resolve a dotted attribute path, e.g., "type.category".
|
|
@@ -66,19 +71,16 @@ class HasChanged(HookCondition):
|
|
|
66
71
|
self.has_changed = has_changed
|
|
67
72
|
|
|
68
73
|
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
|
-
|
|
72
74
|
if not original_instance:
|
|
73
|
-
print(f"DEBUG: No original instance, returning False")
|
|
74
75
|
return False
|
|
75
76
|
|
|
76
77
|
current = resolve_dotted_attr(instance, self.field)
|
|
77
78
|
previous = resolve_dotted_attr(original_instance, self.field)
|
|
78
79
|
|
|
79
|
-
# Add more detailed debugging
|
|
80
80
|
result = (current != previous) == self.has_changed
|
|
81
|
-
|
|
81
|
+
# Only log when there's an actual change to reduce noise
|
|
82
|
+
if result:
|
|
83
|
+
logger.debug(f"HasChanged {self.field} detected change on instance {getattr(instance, 'pk', 'No PK')}")
|
|
82
84
|
return result
|
|
83
85
|
|
|
84
86
|
|
django_bulk_hooks/models.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from django.db import models
|
|
2
3
|
|
|
3
4
|
from django_bulk_hooks.constants import (
|
|
@@ -15,6 +16,8 @@ from django_bulk_hooks.context import HookContext
|
|
|
15
16
|
from django_bulk_hooks.engine import run
|
|
16
17
|
from django_bulk_hooks.manager import BulkHookManager
|
|
17
18
|
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
18
21
|
|
|
19
22
|
class HookModelMixin(models.Model):
|
|
20
23
|
objects = BulkHookManager()
|
|
@@ -56,15 +59,13 @@ class HookModelMixin(models.Model):
|
|
|
56
59
|
def save(self, *args, bypass_hooks=False, **kwargs):
|
|
57
60
|
# If bypass_hooks is True, use base manager to avoid triggering hooks
|
|
58
61
|
if bypass_hooks:
|
|
59
|
-
|
|
60
|
-
f"DEBUG: save() called with bypass_hooks=True for {self.__class__.__name__} pk={self.pk}"
|
|
61
|
-
)
|
|
62
|
+
logger.debug(f"save() called with bypass_hooks=True for {self.__class__.__name__} pk={self.pk}")
|
|
62
63
|
return self._base_manager.save(self, *args, **kwargs)
|
|
63
64
|
|
|
64
65
|
is_create = self.pk is None
|
|
65
66
|
|
|
66
67
|
if is_create:
|
|
67
|
-
|
|
68
|
+
logger.debug(f"save() creating new {self.__class__.__name__} instance")
|
|
68
69
|
# For create operations, we don't have old records
|
|
69
70
|
ctx = HookContext(self.__class__)
|
|
70
71
|
run(self.__class__, BEFORE_CREATE, [self], ctx=ctx)
|
|
@@ -73,9 +74,7 @@ class HookModelMixin(models.Model):
|
|
|
73
74
|
|
|
74
75
|
run(self.__class__, AFTER_CREATE, [self], ctx=ctx)
|
|
75
76
|
else:
|
|
76
|
-
|
|
77
|
-
f"DEBUG: save() updating existing {self.__class__.__name__} instance pk={self.pk}"
|
|
78
|
-
)
|
|
77
|
+
logger.debug(f"save() updating existing {self.__class__.__name__} instance pk={self.pk}")
|
|
79
78
|
# For update operations, we need to get the old record
|
|
80
79
|
try:
|
|
81
80
|
# Use _base_manager to avoid triggering hooks recursively
|
django_bulk_hooks/queryset.py
CHANGED
|
@@ -81,10 +81,10 @@ class HookQuerySetMixin:
|
|
|
81
81
|
|
|
82
82
|
# If we're in a bulk operation context, skip hooks to prevent double execution
|
|
83
83
|
if current_bypass_hooks:
|
|
84
|
-
logger.debug("update skipping hooks (bulk context)")
|
|
84
|
+
logger.debug("update: skipping hooks (bulk context)")
|
|
85
85
|
ctx = HookContext(model_cls, bypass_hooks=True)
|
|
86
86
|
else:
|
|
87
|
-
logger.debug("update running hooks (standalone)")
|
|
87
|
+
logger.debug("update: running hooks (standalone)")
|
|
88
88
|
ctx = HookContext(model_cls, bypass_hooks=False)
|
|
89
89
|
# Run validation hooks first
|
|
90
90
|
engine.run(model_cls, VALIDATE_UPDATE, instances, originals, ctx=ctx)
|
|
@@ -118,10 +118,10 @@ class HookQuerySetMixin:
|
|
|
118
118
|
|
|
119
119
|
# Run AFTER_UPDATE hooks only for standalone updates
|
|
120
120
|
if not current_bypass_hooks:
|
|
121
|
-
logger.debug("update running AFTER_UPDATE")
|
|
121
|
+
logger.debug("update: running AFTER_UPDATE")
|
|
122
122
|
engine.run(model_cls, AFTER_UPDATE, instances, originals, ctx=ctx)
|
|
123
123
|
else:
|
|
124
|
-
logger.debug("update skipping AFTER_UPDATE (bulk context)")
|
|
124
|
+
logger.debug("update: skipping AFTER_UPDATE (bulk context)")
|
|
125
125
|
|
|
126
126
|
return update_count
|
|
127
127
|
|
|
@@ -251,11 +251,11 @@ class HookQuerySetMixin:
|
|
|
251
251
|
break
|
|
252
252
|
|
|
253
253
|
if not bypass_hooks:
|
|
254
|
-
logger.debug("bulk_update
|
|
254
|
+
logger.debug("bulk_update: hooks will run in update()")
|
|
255
255
|
ctx = HookContext(model_cls, bypass_hooks=False)
|
|
256
256
|
originals = [None] * len(objs) # Placeholder for after_update call
|
|
257
257
|
else:
|
|
258
|
-
logger.debug("bulk_update
|
|
258
|
+
logger.debug("bulk_update: hooks bypassed")
|
|
259
259
|
ctx = HookContext(model_cls, bypass_hooks=True)
|
|
260
260
|
originals = [None] * len(objs) # Ensure originals is defined for after_update call
|
|
261
261
|
|
|
@@ -289,9 +289,9 @@ class HookQuerySetMixin:
|
|
|
289
289
|
# Note: We don't run AFTER_UPDATE hooks here to prevent double execution
|
|
290
290
|
# The update() method will handle all hook execution based on thread-local state
|
|
291
291
|
if not bypass_hooks:
|
|
292
|
-
logger.debug("bulk_update skipping AFTER_UPDATE (update() will handle)")
|
|
292
|
+
logger.debug("bulk_update: skipping AFTER_UPDATE (update() will handle)")
|
|
293
293
|
else:
|
|
294
|
-
logger.debug("bulk_update bypassed
|
|
294
|
+
logger.debug("bulk_update: hooks bypassed")
|
|
295
295
|
|
|
296
296
|
return result
|
|
297
297
|
|
django_bulk_hooks/registry.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from collections.abc import Callable
|
|
2
3
|
from typing import Union
|
|
3
4
|
|
|
4
5
|
from django_bulk_hooks.priority import Priority
|
|
5
6
|
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
6
9
|
_hooks: dict[tuple[type, str], list[tuple[type, str, Callable, int]]] = {}
|
|
7
10
|
|
|
8
11
|
|
|
@@ -20,7 +23,9 @@ def register_hook(
|
|
|
20
23
|
def get_hooks(model, event):
|
|
21
24
|
key = (model, event)
|
|
22
25
|
hooks = _hooks.get(key, [])
|
|
23
|
-
|
|
26
|
+
# Only log when hooks are found or for specific events to reduce noise
|
|
27
|
+
if hooks or event in ['after_update', 'before_update', 'after_create', 'before_create']:
|
|
28
|
+
logger.debug(f"get_hooks {model.__name__}.{event} found {len(hooks)} hooks")
|
|
24
29
|
return hooks
|
|
25
30
|
|
|
26
31
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
django_bulk_hooks/__init__.py,sha256=uUgpnb9AWjIAcWNpCMqBcOewSnpJjJYH6cjPbQkzoNU,140
|
|
2
|
-
django_bulk_hooks/conditions.py,sha256=
|
|
2
|
+
django_bulk_hooks/conditions.py,sha256=V_f3Di2uCVUjoyfiU4BQCHmI4uUIRSRroApDcXlvnso,6349
|
|
3
3
|
django_bulk_hooks/constants.py,sha256=3x1H1fSUUNo0DZONN7GUVDuySZctTR-jtByBHmAIX5w,303
|
|
4
4
|
django_bulk_hooks/context.py,sha256=_NbGWTq9s66g0vbFIaqN4GlIHWQmFg3EQ44qY8YvvEg,1537
|
|
5
5
|
django_bulk_hooks/decorators.py,sha256=WD7Jn7QAvY8F4wOsYlIpjoM9-FdHXSKB7hH9ot-lkYQ,4896
|
|
@@ -7,11 +7,11 @@ django_bulk_hooks/engine.py,sha256=t_kvgex6_iZEFc5LK-srBTZPe-1bdlYdip5LfWOc6lc,2
|
|
|
7
7
|
django_bulk_hooks/enums.py,sha256=Zo8_tJzuzZ2IKfVc7gZ-0tWPT8q1QhqZbAyoh9ZVJbs,381
|
|
8
8
|
django_bulk_hooks/handler.py,sha256=xZt8iNdYF-ACz-MnKMY0co6scWINU5V5wC1lyDn844k,4854
|
|
9
9
|
django_bulk_hooks/manager.py,sha256=nfWiwU5-yAoxdnQsUMohxtyCpkV0MBv6X3wmipr9eQY,3697
|
|
10
|
-
django_bulk_hooks/models.py,sha256=
|
|
10
|
+
django_bulk_hooks/models.py,sha256=exnXYVKEVbYAXhChCP8VdWTnKCnm9DiTcokEIBee1I0,4350
|
|
11
11
|
django_bulk_hooks/priority.py,sha256=HG_2D35nga68lBCZmSXTcplXrjFoRgZFRDOy4ROKonY,376
|
|
12
|
-
django_bulk_hooks/queryset.py,sha256=
|
|
13
|
-
django_bulk_hooks/registry.py,sha256=
|
|
14
|
-
django_bulk_hooks-0.1.
|
|
15
|
-
django_bulk_hooks-0.1.
|
|
16
|
-
django_bulk_hooks-0.1.
|
|
17
|
-
django_bulk_hooks-0.1.
|
|
12
|
+
django_bulk_hooks/queryset.py,sha256=YSDCMAf24YLeLJrRKCDYwbZInP2mK_Tcuw3EHLDkv_w,32605
|
|
13
|
+
django_bulk_hooks/registry.py,sha256=8UuhniiH5ChSeOKV1UUbqTEiIu25bZXvcHmkaRbxmME,1131
|
|
14
|
+
django_bulk_hooks-0.1.221.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
|
|
15
|
+
django_bulk_hooks-0.1.221.dist-info/METADATA,sha256=QVFXKdg3v7WcK1IsfDD3h3Nijg3tXdHtlqS6JoGemFo,9061
|
|
16
|
+
django_bulk_hooks-0.1.221.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
17
|
+
django_bulk_hooks-0.1.221.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|