django-bulk-hooks 0.1.245__tar.gz → 0.1.247__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.245 → django_bulk_hooks-0.1.247}/PKG-INFO +1 -1
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/queryset.py +36 -18
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/pyproject.toml +1 -1
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/LICENSE +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/README.md +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/__init__.py +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/conditions.py +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/constants.py +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/context.py +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/decorators.py +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/engine.py +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/enums.py +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/handler.py +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/manager.py +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/models.py +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/priority.py +0 -0
- {django_bulk_hooks-0.1.245 → django_bulk_hooks-0.1.247}/django_bulk_hooks/registry.py +0 -0
|
@@ -172,21 +172,18 @@ class HookQuerySetMixin:
|
|
|
172
172
|
logger.debug("update: running hooks with Salesforce-style behavior")
|
|
173
173
|
ctx = HookContext(model_cls, bypass_hooks=False)
|
|
174
174
|
|
|
175
|
-
#
|
|
176
|
-
|
|
175
|
+
# Run validation hooks first
|
|
176
|
+
engine.run(model_cls, VALIDATE_UPDATE, instances, originals, ctx=ctx)
|
|
177
|
+
|
|
178
|
+
# For Subquery updates, skip BEFORE_UPDATE hooks here - they'll run after refresh
|
|
177
179
|
if not has_subquery:
|
|
178
|
-
#
|
|
179
|
-
engine.run(model_cls, VALIDATE_UPDATE, instances, originals, ctx=ctx)
|
|
180
|
-
# Then run BEFORE_UPDATE hooks
|
|
180
|
+
# Then run BEFORE_UPDATE hooks for non-Subquery updates
|
|
181
181
|
engine.run(model_cls, BEFORE_UPDATE, instances, originals, ctx=ctx)
|
|
182
182
|
|
|
183
183
|
# Persist any additional field mutations made by BEFORE_UPDATE hooks.
|
|
184
184
|
# Build CASE statements per modified field not already present in kwargs.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if not has_subquery
|
|
188
|
-
else set()
|
|
189
|
-
)
|
|
185
|
+
# Note: For Subquery updates, this will be empty since hooks haven't run yet
|
|
186
|
+
modified_fields = self._detect_modified_fields(instances, originals)
|
|
190
187
|
extra_fields = [f for f in modified_fields if f not in kwargs]
|
|
191
188
|
if extra_fields:
|
|
192
189
|
case_statements = {}
|
|
@@ -384,7 +381,7 @@ class HookQuerySetMixin:
|
|
|
384
381
|
raise
|
|
385
382
|
|
|
386
383
|
# If we used Subquery objects, refresh the instances to get computed values
|
|
387
|
-
# and
|
|
384
|
+
# and run BEFORE_UPDATE hooks so HasChanged conditions work correctly
|
|
388
385
|
if has_subquery and instances and not current_bypass_hooks:
|
|
389
386
|
logger.debug(
|
|
390
387
|
"Refreshing instances with Subquery computed values before running hooks"
|
|
@@ -395,26 +392,47 @@ class HookQuerySetMixin:
|
|
|
395
392
|
obj.pk: obj for obj in model_cls._base_manager.filter(pk__in=pks)
|
|
396
393
|
}
|
|
397
394
|
|
|
398
|
-
# Bulk update all instances in memory
|
|
395
|
+
# Bulk update all instances in memory and save pre-hook state
|
|
396
|
+
pre_hook_state = {}
|
|
399
397
|
for instance in instances:
|
|
400
398
|
if instance.pk in refreshed_instances:
|
|
401
399
|
refreshed_instance = refreshed_instances[instance.pk]
|
|
402
|
-
#
|
|
400
|
+
# Save current state before modifying for hook comparison
|
|
401
|
+
pre_hook_values = {}
|
|
403
402
|
for field in model_cls._meta.fields:
|
|
404
403
|
if field.name != "id":
|
|
404
|
+
pre_hook_values[field.name] = getattr(refreshed_instance, field.name)
|
|
405
405
|
setattr(
|
|
406
406
|
instance,
|
|
407
407
|
field.name,
|
|
408
408
|
getattr(refreshed_instance, field.name),
|
|
409
409
|
)
|
|
410
|
+
pre_hook_state[instance.pk] = pre_hook_values
|
|
410
411
|
|
|
411
|
-
# Now run
|
|
412
|
-
logger.debug("Running hooks after Subquery refresh")
|
|
413
|
-
# Run validation hooks first
|
|
414
|
-
engine.run(model_cls, VALIDATE_UPDATE, instances, originals, ctx=ctx)
|
|
415
|
-
# Then run BEFORE_UPDATE hooks
|
|
412
|
+
# Now run BEFORE_UPDATE hooks with refreshed instances so conditions work
|
|
413
|
+
logger.debug("Running BEFORE_UPDATE hooks after Subquery refresh")
|
|
416
414
|
engine.run(model_cls, BEFORE_UPDATE, instances, originals, ctx=ctx)
|
|
417
415
|
|
|
416
|
+
# Check if hooks modified any fields and persist them with bulk_update
|
|
417
|
+
hook_modified_fields = set()
|
|
418
|
+
for instance in instances:
|
|
419
|
+
if instance.pk in pre_hook_state:
|
|
420
|
+
pre_hook_values = pre_hook_state[instance.pk]
|
|
421
|
+
for field_name, pre_hook_value in pre_hook_values.items():
|
|
422
|
+
current_value = getattr(instance, field_name)
|
|
423
|
+
if current_value != pre_hook_value:
|
|
424
|
+
hook_modified_fields.add(field_name)
|
|
425
|
+
|
|
426
|
+
hook_modified_fields = list(hook_modified_fields)
|
|
427
|
+
if hook_modified_fields:
|
|
428
|
+
logger.debug(
|
|
429
|
+
f"Running bulk_update for hook-modified fields: {hook_modified_fields}"
|
|
430
|
+
)
|
|
431
|
+
# Use bulk_update to persist hook modifications, bypassing hooks to avoid recursion
|
|
432
|
+
model_cls.objects.bulk_update(
|
|
433
|
+
instances, hook_modified_fields, bypass_hooks=True
|
|
434
|
+
)
|
|
435
|
+
|
|
418
436
|
# Salesforce-style: Always run AFTER_UPDATE hooks unless explicitly bypassed
|
|
419
437
|
if not current_bypass_hooks:
|
|
420
438
|
logger.debug("update: running AFTER_UPDATE")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "django-bulk-hooks"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.247"
|
|
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
|