django-bulk-hooks 0.1.242__tar.gz → 0.1.244__tar.gz
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-0.1.242 → django_bulk_hooks-0.1.244}/PKG-INFO +1 -1
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/queryset.py +39 -34
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/pyproject.toml +1 -1
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/LICENSE +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/README.md +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/__init__.py +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/conditions.py +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/constants.py +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/context.py +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/decorators.py +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/engine.py +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/enums.py +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/handler.py +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/manager.py +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/models.py +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/priority.py +0 -0
- {django_bulk_hooks-0.1.242 → django_bulk_hooks-0.1.244}/django_bulk_hooks/registry.py +0 -0
|
@@ -125,41 +125,53 @@ class HookQuerySetMixin:
|
|
|
125
125
|
# to in-memory instances before running BEFORE_UPDATE hooks. Hooks must not
|
|
126
126
|
# receive unresolved expression objects.
|
|
127
127
|
per_object_values = get_bulk_update_value_map()
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
128
|
+
|
|
129
|
+
# For Subquery updates, skip all in-memory field assignments to prevent
|
|
130
|
+
# expression objects from reaching hooks
|
|
131
|
+
if has_subquery:
|
|
132
|
+
logger.debug(
|
|
133
|
+
"Skipping in-memory field assignments due to Subquery detection"
|
|
134
|
+
)
|
|
135
|
+
else:
|
|
136
|
+
for obj in instances:
|
|
137
|
+
if per_object_values and obj.pk in per_object_values:
|
|
138
|
+
for field, value in per_object_values[obj.pk].items():
|
|
139
|
+
setattr(obj, field, value)
|
|
140
|
+
else:
|
|
141
|
+
for field, value in kwargs.items():
|
|
142
|
+
# Skip assigning expression-like objects (they will be handled at DB level)
|
|
143
|
+
is_expression_like = hasattr(value, "resolve_expression")
|
|
144
|
+
if is_expression_like:
|
|
145
|
+
# Special-case Value() which can be unwrapped safely
|
|
146
|
+
if isinstance(value, Value):
|
|
147
|
+
try:
|
|
148
|
+
setattr(obj, field, value.value)
|
|
149
|
+
except Exception:
|
|
150
|
+
# If Value cannot be unwrapped for any reason, skip assignment
|
|
151
|
+
continue
|
|
152
|
+
else:
|
|
153
|
+
# Do not assign unresolved expressions to in-memory objects
|
|
154
|
+
logger.debug(
|
|
155
|
+
f"Skipping assignment of expression {type(value).__name__} to field {field}"
|
|
156
|
+
)
|
|
144
157
|
continue
|
|
145
158
|
else:
|
|
146
|
-
|
|
147
|
-
continue
|
|
148
|
-
else:
|
|
149
|
-
setattr(obj, field, value)
|
|
159
|
+
setattr(obj, field, value)
|
|
150
160
|
|
|
151
|
-
#
|
|
161
|
+
# Salesforce-style trigger behavior: Always run hooks, rely on Django's stack overflow protection
|
|
152
162
|
from django_bulk_hooks.context import get_bypass_hooks
|
|
153
163
|
|
|
154
164
|
current_bypass_hooks = get_bypass_hooks()
|
|
155
165
|
|
|
156
|
-
#
|
|
166
|
+
# Only skip hooks if explicitly bypassed (not for recursion prevention)
|
|
157
167
|
if current_bypass_hooks:
|
|
158
|
-
logger.debug("update:
|
|
168
|
+
logger.debug("update: hooks explicitly bypassed")
|
|
159
169
|
ctx = HookContext(model_cls, bypass_hooks=True)
|
|
160
170
|
else:
|
|
161
|
-
|
|
171
|
+
# Always run hooks - Django will handle stack overflow protection
|
|
172
|
+
logger.debug("update: running hooks with Salesforce-style behavior")
|
|
162
173
|
ctx = HookContext(model_cls, bypass_hooks=False)
|
|
174
|
+
|
|
163
175
|
# Run validation hooks first
|
|
164
176
|
engine.run(model_cls, VALIDATE_UPDATE, instances, originals, ctx=ctx)
|
|
165
177
|
# Then run BEFORE_UPDATE hooks
|
|
@@ -385,19 +397,12 @@ class HookQuerySetMixin:
|
|
|
385
397
|
getattr(refreshed_instance, field.name),
|
|
386
398
|
)
|
|
387
399
|
|
|
388
|
-
#
|
|
389
|
-
|
|
390
|
-
# because subqueries bypass the normal object-level update flow
|
|
391
|
-
should_run_hooks = (
|
|
392
|
-
not current_bypass_hooks
|
|
393
|
-
or has_subquery # Always run hooks for subquery operations
|
|
394
|
-
)
|
|
395
|
-
|
|
396
|
-
if should_run_hooks:
|
|
400
|
+
# Salesforce-style: Always run AFTER_UPDATE hooks unless explicitly bypassed
|
|
401
|
+
if not current_bypass_hooks:
|
|
397
402
|
logger.debug("update: running AFTER_UPDATE")
|
|
398
403
|
engine.run(model_cls, AFTER_UPDATE, instances, originals, ctx=ctx)
|
|
399
404
|
else:
|
|
400
|
-
logger.debug("update:
|
|
405
|
+
logger.debug("update: AFTER_UPDATE explicitly bypassed")
|
|
401
406
|
|
|
402
407
|
return update_count
|
|
403
408
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "django-bulk-hooks"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.244"
|
|
4
4
|
description = "Hook-style hooks for Django bulk operations like bulk_create and bulk_update."
|
|
5
5
|
authors = ["Konrad Beck <konrad.beck@merchantcapital.co.za>"]
|
|
6
6
|
readme = "README.md"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|