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

@@ -172,14 +172,17 @@ 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
- # Run hooks before database update for both Subquery and non-Subquery cases
176
175
  # Run validation hooks first
177
176
  engine.run(model_cls, VALIDATE_UPDATE, instances, originals, ctx=ctx)
178
- # Then run BEFORE_UPDATE hooks
179
- engine.run(model_cls, BEFORE_UPDATE, instances, originals, ctx=ctx)
177
+
178
+ # For Subquery updates, skip BEFORE_UPDATE hooks here - they'll run after refresh
179
+ if not has_subquery:
180
+ # Then run BEFORE_UPDATE hooks for non-Subquery updates
181
+ engine.run(model_cls, BEFORE_UPDATE, instances, originals, ctx=ctx)
180
182
 
181
183
  # Persist any additional field mutations made by BEFORE_UPDATE hooks.
182
184
  # Build CASE statements per modified field not already present in kwargs.
185
+ # Note: For Subquery updates, this will be empty since hooks haven't run yet
183
186
  modified_fields = self._detect_modified_fields(instances, originals)
184
187
  extra_fields = [f for f in modified_fields if f not in kwargs]
185
188
  if extra_fields:
@@ -378,7 +381,7 @@ class HookQuerySetMixin:
378
381
  raise
379
382
 
380
383
  # If we used Subquery objects, refresh the instances to get computed values
381
- # for AFTER_UPDATE hooks so HasChanged conditions work correctly
384
+ # and run BEFORE_UPDATE hooks so HasChanged conditions work correctly
382
385
  if has_subquery and instances and not current_bypass_hooks:
383
386
  logger.debug(
384
387
  "Refreshing instances with Subquery computed values before running hooks"
@@ -389,20 +392,46 @@ class HookQuerySetMixin:
389
392
  obj.pk: obj for obj in model_cls._base_manager.filter(pk__in=pks)
390
393
  }
391
394
 
392
- # Bulk update all instances in memory
395
+ # Bulk update all instances in memory and save pre-hook state
396
+ pre_hook_state = {}
393
397
  for instance in instances:
394
398
  if instance.pk in refreshed_instances:
395
399
  refreshed_instance = refreshed_instances[instance.pk]
396
- # Update all fields except primary key
400
+ # Save current state before modifying for hook comparison
401
+ pre_hook_values = {}
397
402
  for field in model_cls._meta.fields:
398
403
  if field.name != "id":
404
+ pre_hook_values[field.name] = getattr(refreshed_instance, field.name)
399
405
  setattr(
400
406
  instance,
401
407
  field.name,
402
408
  getattr(refreshed_instance, field.name),
403
409
  )
410
+ pre_hook_state[instance.pk] = pre_hook_values
411
+
412
+ # Now run BEFORE_UPDATE hooks with refreshed instances so conditions work
413
+ logger.debug("Running BEFORE_UPDATE hooks after Subquery refresh")
414
+ engine.run(model_cls, BEFORE_UPDATE, instances, originals, ctx=ctx)
404
415
 
405
- logger.debug("Running hooks after Subquery refresh")
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
+ )
406
435
 
407
436
  # Salesforce-style: Always run AFTER_UPDATE hooks unless explicitly bypassed
408
437
  if not current_bypass_hooks:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-bulk-hooks
3
- Version: 0.1.246
3
+ Version: 0.1.247
4
4
  Summary: Hook-style hooks for Django bulk operations like bulk_create and bulk_update.
5
5
  Home-page: https://github.com/AugendLimited/django-bulk-hooks
6
6
  License: MIT
@@ -9,9 +9,9 @@ django_bulk_hooks/handler.py,sha256=e_GACTQT-pFF-zL7POeo232MgOikUoCLcxDVInAUiBw,
9
9
  django_bulk_hooks/manager.py,sha256=nfWiwU5-yAoxdnQsUMohxtyCpkV0MBv6X3wmipr9eQY,3697
10
10
  django_bulk_hooks/models.py,sha256=WtSfc4GBOG_oOt8n37cVvid0MtFIGze9JYKSixil2y0,4370
11
11
  django_bulk_hooks/priority.py,sha256=HG_2D35nga68lBCZmSXTcplXrjFoRgZFRDOy4ROKonY,376
12
- django_bulk_hooks/queryset.py,sha256=4M5G5hbpEJQ8PvP9ASMY_vIZO3DKJhXxudQiPCMBJc4,50410
12
+ django_bulk_hooks/queryset.py,sha256=CHcQzKNQvdYWnIUHqG5tkngWtiBKEvyEeJMXUpNkTzc,52108
13
13
  django_bulk_hooks/registry.py,sha256=GRUTGVQEO2sdkC9OaZ9Q3U7mM-3Ix83uTyvrlTtpatw,1317
14
- django_bulk_hooks-0.1.246.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
15
- django_bulk_hooks-0.1.246.dist-info/METADATA,sha256=f2S2FbuQwyGLpkUhfzwP3OwWonklqvpEwacnJQpyQJs,9049
16
- django_bulk_hooks-0.1.246.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
17
- django_bulk_hooks-0.1.246.dist-info/RECORD,,
14
+ django_bulk_hooks-0.1.247.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
15
+ django_bulk_hooks-0.1.247.dist-info/METADATA,sha256=yyIsZ_9DgoIzDl7y6fCvPTW2W-Asc7Dtfuo0Tlj5fcA,9049
16
+ django_bulk_hooks-0.1.247.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
17
+ django_bulk_hooks-0.1.247.dist-info/RECORD,,