django-bulk-hooks 0.1.173__tar.gz → 0.1.176__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.

Files changed (17) hide show
  1. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/PKG-INFO +3 -3
  2. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/manager.py +7 -5
  3. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/queryset.py +112 -151
  4. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/pyproject.toml +1 -1
  5. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/LICENSE +0 -0
  6. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/README.md +0 -0
  7. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/__init__.py +0 -0
  8. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/conditions.py +0 -0
  9. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/constants.py +0 -0
  10. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/context.py +0 -0
  11. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/decorators.py +0 -0
  12. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/engine.py +0 -0
  13. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/enums.py +0 -0
  14. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/handler.py +0 -0
  15. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/models.py +0 -0
  16. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/priority.py +0 -0
  17. {django_bulk_hooks-0.1.173 → django_bulk_hooks-0.1.176}/django_bulk_hooks/registry.py +0 -0
@@ -1,8 +1,7 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: django-bulk-hooks
3
- Version: 0.1.173
3
+ Version: 0.1.176
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
 
@@ -58,12 +58,12 @@ class BulkHookManager(models.Manager):
58
58
  """
59
59
  import inspect
60
60
 
61
- qs = self.get_queryset()
61
+ queryset = self.get_queryset()
62
62
 
63
63
  # Check if this is our HookQuerySet or a different QuerySet
64
64
  if (
65
- hasattr(qs, "bulk_create")
66
- and "bypass_hooks" in inspect.signature(qs.bulk_create).parameters
65
+ hasattr(queryset, "bulk_create")
66
+ and "bypass_hooks" in inspect.signature(queryset.bulk_create).parameters
67
67
  ):
68
68
  # Our HookQuerySet - pass all parameters
69
69
  kwargs = {
@@ -73,13 +73,15 @@ class BulkHookManager(models.Manager):
73
73
  "update_fields": update_fields,
74
74
  "unique_fields": unique_fields,
75
75
  }
76
- return qs.bulk_create(
76
+ return queryset.bulk_create(
77
77
  objs,
78
78
  bypass_hooks=bypass_hooks,
79
79
  bypass_validation=bypass_validation,
80
80
  **kwargs,
81
81
  )
82
82
  else:
83
+ print("Different QuerySet")
84
+
83
85
  # Different QuerySet - only pass standard parameters
84
86
  kwargs = {
85
87
  "batch_size": batch_size,
@@ -88,7 +90,7 @@ class BulkHookManager(models.Manager):
88
90
  "update_fields": update_fields,
89
91
  "unique_fields": unique_fields,
90
92
  }
91
- return qs.bulk_create(objs, **kwargs)
93
+ return queryset.bulk_create(objs, **kwargs)
92
94
 
93
95
  def bulk_delete(
94
96
  self, objs, batch_size=None, bypass_hooks=False, bypass_validation=False
@@ -24,8 +24,23 @@ class HookQuerySet(models.QuerySet):
24
24
  objs = list(self)
25
25
  if not objs:
26
26
  return 0
27
- # Call the base QuerySet implementation to avoid recursion
28
- return super().bulk_delete(objs)
27
+
28
+ model_cls = self.model
29
+ ctx = HookContext(model_cls)
30
+
31
+ # Run validation hooks first
32
+ engine.run(model_cls, VALIDATE_DELETE, objs, ctx=ctx)
33
+
34
+ # Then run business logic hooks
35
+ engine.run(model_cls, BEFORE_DELETE, objs, ctx=ctx)
36
+
37
+ # Use Django's standard delete() method
38
+ result = super().delete()
39
+
40
+ # Run AFTER_DELETE hooks
41
+ engine.run(model_cls, AFTER_DELETE, objs, ctx=ctx)
42
+
43
+ return result
29
44
 
30
45
  @transaction.atomic
31
46
  def update(self, **kwargs):
@@ -38,7 +53,9 @@ class HookQuerySet(models.QuerySet):
38
53
 
39
54
  # Load originals for hook comparison and ensure they match the order of instances
40
55
  # Use the base manager to avoid recursion
41
- original_map = {obj.pk: obj for obj in model_cls._base_manager.filter(pk__in=pks)}
56
+ original_map = {
57
+ obj.pk: obj for obj in model_cls._base_manager.filter(pk__in=pks)
58
+ }
42
59
  originals = [original_map.get(obj.pk) for obj in instances]
43
60
 
44
61
  # Apply field updates to instances
@@ -92,6 +109,14 @@ class HookQuerySet(models.QuerySet):
92
109
  # trickier so it's not done yet.
93
110
  if batch_size is not None and batch_size <= 0:
94
111
  raise ValueError("Batch size must be a positive integer.")
112
+
113
+ if not objs:
114
+ return objs
115
+
116
+ if any(not isinstance(obj, model_cls) for obj in objs):
117
+ raise TypeError(
118
+ f"bulk_create expected instances of {model_cls.__name__}, but got {set(type(obj).__name__ for obj in objs)}"
119
+ )
95
120
 
96
121
  # Check for MTI - if we detect multi-table inheritance, we need special handling
97
122
  # This follows Django's approach: check that the parents share the same concrete model
@@ -104,55 +129,35 @@ class HookQuerySet(models.QuerySet):
104
129
  is_mti = True
105
130
  break
106
131
 
107
- if not objs:
108
- return objs
109
-
110
- if any(not isinstance(obj, model_cls) for obj in objs):
111
- raise TypeError(
112
- f"bulk_create expected instances of {model_cls.__name__}, but got {set(type(obj).__name__ for obj in objs)}"
113
- )
114
-
115
132
  # Fire hooks before DB ops
116
133
  if not bypass_hooks:
117
- print(f"DEBUG: Firing BEFORE_CREATE hooks for {model_cls}")
118
- print(f"DEBUG: Number of objects: {len(objs)}")
119
- print(f"DEBUG: Object types: {[type(obj) for obj in objs]}")
120
- print(f"DEBUG: QuerySet type: {type(self)}")
121
- print(f"DEBUG: Is this HookQuerySet? {isinstance(self, HookQuerySet)}")
122
134
  ctx = HookContext(model_cls)
123
135
  if not bypass_validation:
124
- print(f"DEBUG: Running VALIDATE_CREATE hooks")
125
136
  engine.run(model_cls, VALIDATE_CREATE, objs, ctx=ctx)
126
- print(f"DEBUG: Running BEFORE_CREATE hooks")
127
137
  engine.run(model_cls, BEFORE_CREATE, objs, ctx=ctx)
128
- else:
129
- print(f"DEBUG: Skipping hooks due to bypass_hooks=True for {model_cls}")
130
138
 
131
139
  # For MTI models, we need to handle them specially
132
140
  if is_mti:
133
141
  # Use our MTI-specific logic
134
142
  # Filter out custom parameters that Django's bulk_create doesn't accept
135
143
  mti_kwargs = {
136
- 'batch_size': batch_size,
137
- 'ignore_conflicts': ignore_conflicts,
138
- 'update_conflicts': update_conflicts,
139
- 'update_fields': update_fields,
140
- 'unique_fields': unique_fields,
144
+ "batch_size": batch_size,
145
+ "ignore_conflicts": ignore_conflicts,
146
+ "update_conflicts": update_conflicts,
147
+ "update_fields": update_fields,
148
+ "unique_fields": unique_fields,
141
149
  }
142
150
  # Remove custom hook kwargs if present in self.bulk_create signature
143
151
  result = self._mti_bulk_create(
144
152
  objs,
145
- **{k: v for k, v in mti_kwargs.items() if k not in ['bypass_hooks', 'bypass_validation']}
153
+ mti_kwargs,
146
154
  )
147
155
  else:
148
156
  # For single-table models, use Django's built-in bulk_create
149
157
  # but we need to call it on the base manager to avoid recursion
150
158
  # Filter out custom parameters that Django's bulk_create doesn't accept
151
159
 
152
- # Use Django's original QuerySet to avoid recursive calls
153
- from django.db.models import QuerySet
154
- original_qs = QuerySet(model_cls, using=self.db)
155
- result = original_qs.bulk_create(
160
+ result = super().bulk_create(
156
161
  objs,
157
162
  batch_size=batch_size,
158
163
  ignore_conflicts=ignore_conflicts,
@@ -163,37 +168,19 @@ class HookQuerySet(models.QuerySet):
163
168
 
164
169
  # Fire AFTER_CREATE hooks
165
170
  if not bypass_hooks:
166
- print(f"DEBUG: Firing AFTER_CREATE hooks for {model_cls}")
167
- print(f"DEBUG: Number of objects: {len(objs)}")
168
- print(f"DEBUG: QuerySet type: {type(self)}")
169
- print(f"DEBUG: Is this HookQuerySet? {isinstance(self, HookQuerySet)}")
170
171
  engine.run(model_cls, AFTER_CREATE, objs, ctx=ctx)
171
- else:
172
- print(f"DEBUG: Skipping AFTER_CREATE hooks due to bypass_hooks=True for {model_cls}")
173
172
 
174
173
  return result
175
174
 
176
175
  @transaction.atomic
177
- def bulk_update(self, objs, fields, bypass_hooks=False, bypass_validation=False, **kwargs):
176
+ def bulk_update(
177
+ self, objs, fields, bypass_hooks=False, bypass_validation=False, **kwargs
178
+ ):
178
179
  """
179
180
  Bulk update objects in the database.
180
181
  """
181
- import inspect
182
- print(f"DEBUG: QuerySet.bulk_update called with:")
183
- print(f" - self: {type(self)}")
184
- print(f" - objs: {type(objs)}")
185
- print(f" - fields: {fields}")
186
- print(f" - bypass_hooks: {bypass_hooks}")
187
- print(f" - bypass_validation: {bypass_validation}")
188
- print(f" - kwargs: {kwargs}")
189
- print(f"DEBUG: Method signature: {inspect.signature(self.bulk_update)}")
190
-
191
182
  model_cls = self.model
192
- print(f"DEBUG: Model class: {model_cls}")
193
- print(f"DEBUG: bypass_hooks value: {bypass_hooks}")
194
- print(f"DEBUG: QuerySet type: {type(self)}")
195
- print(f"DEBUG: Is this HookQuerySet? {isinstance(self, HookQuerySet)}")
196
-
183
+
197
184
  if not objs:
198
185
  return []
199
186
 
@@ -207,7 +194,9 @@ class HookQuerySet(models.QuerySet):
207
194
  # Use the base manager to avoid recursion
208
195
  original_map = {
209
196
  obj.pk: obj
210
- for obj in model_cls._base_manager.filter(pk__in=[obj.pk for obj in objs])
197
+ for obj in model_cls._base_manager.filter(
198
+ pk__in=[obj.pk for obj in objs]
199
+ )
211
200
  }
212
201
  originals = [original_map.get(obj.pk) for obj in objs]
213
202
 
@@ -219,12 +208,7 @@ class HookQuerySet(models.QuerySet):
219
208
 
220
209
  # Then run business logic hooks
221
210
  if not bypass_hooks:
222
- print(f"DEBUG: Firing BEFORE_UPDATE hooks for {model_cls}")
223
- print(f"DEBUG: Number of objects: {len(objs)}")
224
- print(f"DEBUG: Object types: {[type(obj) for obj in objs]}")
225
211
  engine.run(model_cls, BEFORE_UPDATE, objs, originals, ctx=ctx)
226
- else:
227
- print(f"DEBUG: Skipping hooks due to bypass_hooks=True for {model_cls}")
228
212
 
229
213
  # Automatically detect fields that were modified during BEFORE_UPDATE hooks
230
214
  modified_fields = self._detect_modified_fields(objs, originals)
@@ -234,55 +218,15 @@ class HookQuerySet(models.QuerySet):
234
218
  fields_set.update(modified_fields)
235
219
  fields = list(fields_set)
236
220
 
237
- for i in range(0, len(objs), self.CHUNK_SIZE):
238
- chunk = objs[i : i + self.CHUNK_SIZE]
239
-
240
- # Call the base implementation to avoid re-triggering this method
241
- # Filter out custom parameters that Django's bulk_update doesn't accept
242
- django_kwargs = {k: v for k, v in kwargs.items() if k not in ['bypass_hooks', 'bypass_validation']}
243
- super().bulk_update(chunk, fields, **django_kwargs)
221
+ django_kwargs = {
222
+ k: v
223
+ for k, v in kwargs.items()
224
+ if k not in ["bypass_hooks", "bypass_validation"]
225
+ }
226
+ super().bulk_update(objs, fields, **django_kwargs)
244
227
 
245
228
  if not bypass_hooks:
246
- print(f"DEBUG: Firing AFTER_UPDATE hooks for {model_cls}")
247
- print(f"DEBUG: Number of objects: {len(objs)}")
248
229
  engine.run(model_cls, AFTER_UPDATE, objs, originals, ctx=ctx)
249
- else:
250
- print(f"DEBUG: Skipping AFTER_UPDATE hooks due to bypass_hooks=True for {model_cls}")
251
-
252
- return objs
253
-
254
- @transaction.atomic
255
- def bulk_delete(
256
- self, objs, batch_size=None, bypass_hooks=False, bypass_validation=False
257
- ):
258
- if not objs:
259
- return []
260
-
261
- model_cls = self.model
262
-
263
- if any(not isinstance(obj, model_cls) for obj in objs):
264
- raise TypeError(
265
- f"bulk_delete expected instances of {model_cls.__name__}, but got {set(type(obj).__name__ for obj in objs)}"
266
- )
267
-
268
- ctx = HookContext(model_cls)
269
-
270
- if not bypass_hooks:
271
- # Run validation hooks first
272
- if not bypass_validation:
273
- engine.run(model_cls, VALIDATE_DELETE, objs, ctx=ctx)
274
-
275
- # Then run business logic hooks
276
- engine.run(model_cls, BEFORE_DELETE, objs, ctx=ctx)
277
-
278
- pks = [obj.pk for obj in objs if obj.pk is not None]
279
-
280
- # Call the base QuerySet implementation to avoid recursion
281
- # The hooks have already been fired above, so we don't need them again
282
- super().bulk_delete(objs, batch_size=batch_size)
283
-
284
- if not bypass_hooks:
285
- engine.run(model_cls, AFTER_DELETE, objs, ctx=ctx)
286
230
 
287
231
  return objs
288
232
 
@@ -350,7 +294,11 @@ class HookQuerySet(models.QuerySet):
350
294
  Sets auto_now_add/auto_now fields for each model in the chain.
351
295
  """
352
296
  # Remove custom hook kwargs before passing to Django internals
353
- django_kwargs = {k: v for k, v in kwargs.items() if k not in ['bypass_hooks', 'bypass_validation']}
297
+ django_kwargs = {
298
+ k: v
299
+ for k, v in kwargs.items()
300
+ if k not in ["bypass_hooks", "bypass_validation"]
301
+ }
354
302
  if inheritance_chain is None:
355
303
  inheritance_chain = self._get_inheritance_chain()
356
304
 
@@ -383,9 +331,9 @@ class HookQuerySet(models.QuerySet):
383
331
 
384
332
  # Step 1: Do O(n) normal inserts into parent tables to get primary keys back
385
333
  # Get bypass_hooks from kwargs
386
- bypass_hooks = kwargs.get('bypass_hooks', False)
387
- bypass_validation = kwargs.get('bypass_validation', False)
388
-
334
+ bypass_hooks = kwargs.get("bypass_hooks", False)
335
+ bypass_validation = kwargs.get("bypass_validation", False)
336
+
389
337
  for obj in batch:
390
338
  parent_instances = {}
391
339
  current_parent = None
@@ -393,32 +341,35 @@ class HookQuerySet(models.QuerySet):
393
341
  parent_obj = self._create_parent_instance(
394
342
  obj, model_class, current_parent
395
343
  )
396
-
344
+
397
345
  # Fire parent hooks if not bypassed
398
346
  if not bypass_hooks:
399
347
  ctx = HookContext(model_class)
400
348
  if not bypass_validation:
401
349
  engine.run(model_class, VALIDATE_CREATE, [parent_obj], ctx=ctx)
402
350
  engine.run(model_class, BEFORE_CREATE, [parent_obj], ctx=ctx)
403
-
351
+
404
352
  # Use Django's base manager to create the object and get PKs back
405
353
  # This bypasses hooks and the MTI exception
406
354
  field_values = {
407
355
  field.name: getattr(parent_obj, field.name)
408
356
  for field in model_class._meta.local_fields
409
- if hasattr(parent_obj, field.name) and getattr(parent_obj, field.name) is not None
357
+ if hasattr(parent_obj, field.name)
358
+ and getattr(parent_obj, field.name) is not None
410
359
  }
411
- created_obj = model_class._base_manager.using(self.db).create(**field_values)
412
-
360
+ created_obj = model_class._base_manager.using(self.db).create(
361
+ **field_values
362
+ )
363
+
413
364
  # Update the parent_obj with the created object's PK
414
365
  parent_obj.pk = created_obj.pk
415
366
  parent_obj._state.adding = False
416
367
  parent_obj._state.db = self.db
417
-
368
+
418
369
  # Fire AFTER_CREATE hooks for parent
419
370
  if not bypass_hooks:
420
371
  engine.run(model_class, AFTER_CREATE, [parent_obj], ctx=ctx)
421
-
372
+
422
373
  parent_instances[model_class] = parent_obj
423
374
  current_parent = parent_obj
424
375
  parent_objects_map[id(obj)] = parent_instances
@@ -436,10 +387,10 @@ class HookQuerySet(models.QuerySet):
436
387
  if all_child_objects:
437
388
  # Get the base manager's queryset
438
389
  base_qs = child_model._base_manager.using(self.db)
439
-
390
+
440
391
  # Use Django's exact approach: call _prepare_for_bulk_create then partition
441
392
  base_qs._prepare_for_bulk_create(all_child_objects)
442
-
393
+
443
394
  # Implement our own partition since itertools.partition might not be available
444
395
  objs_without_pk, objs_with_pk = [], []
445
396
  for obj in all_child_objects:
@@ -447,44 +398,50 @@ class HookQuerySet(models.QuerySet):
447
398
  objs_with_pk.append(obj)
448
399
  else:
449
400
  objs_without_pk.append(obj)
450
-
401
+
451
402
  # Use Django's internal _batched_insert method
452
403
  opts = child_model._meta
453
404
  # For child models in MTI, we need to include the foreign key to the parent
454
405
  # but exclude the primary key since it's inherited
455
-
406
+
456
407
  # Include all local fields except generated ones
457
408
  # We need to include the foreign key to the parent (business_ptr)
458
409
  fields = [f for f in opts.local_fields if not f.generated]
459
-
410
+
460
411
  with transaction.atomic(using=self.db, savepoint=False):
461
- if objs_with_pk:
462
- returned_columns = base_qs._batched_insert(
463
- objs_with_pk,
464
- fields,
465
- batch_size=len(objs_with_pk), # Use actual batch size
466
- )
467
- for obj_with_pk, results in zip(objs_with_pk, returned_columns):
468
- for result, field in zip(results, opts.db_returning_fields):
469
- if field != opts.pk:
470
- setattr(obj_with_pk, field.attname, result)
471
- for obj_with_pk in objs_with_pk:
472
- obj_with_pk._state.adding = False
473
- obj_with_pk._state.db = self.db
474
-
475
- if objs_without_pk:
476
- # For objects without PK, we still need to exclude primary key fields
477
- fields = [f for f in fields if not isinstance(f, AutoField) and not f.primary_key]
478
- returned_columns = base_qs._batched_insert(
479
- objs_without_pk,
480
- fields,
481
- batch_size=len(objs_without_pk), # Use actual batch size
482
- )
483
- for obj_without_pk, results in zip(objs_without_pk, returned_columns):
484
- for result, field in zip(results, opts.db_returning_fields):
485
- setattr(obj_without_pk, field.attname, result)
486
- obj_without_pk._state.adding = False
487
- obj_without_pk._state.db = self.db
412
+ if objs_with_pk:
413
+ returned_columns = base_qs._batched_insert(
414
+ objs_with_pk,
415
+ fields,
416
+ batch_size=len(objs_with_pk), # Use actual batch size
417
+ )
418
+ for obj_with_pk, results in zip(objs_with_pk, returned_columns):
419
+ for result, field in zip(results, opts.db_returning_fields):
420
+ if field != opts.pk:
421
+ setattr(obj_with_pk, field.attname, result)
422
+ for obj_with_pk in objs_with_pk:
423
+ obj_with_pk._state.adding = False
424
+ obj_with_pk._state.db = self.db
425
+
426
+ if objs_without_pk:
427
+ # For objects without PK, we still need to exclude primary key fields
428
+ fields = [
429
+ f
430
+ for f in fields
431
+ if not isinstance(f, AutoField) and not f.primary_key
432
+ ]
433
+ returned_columns = base_qs._batched_insert(
434
+ objs_without_pk,
435
+ fields,
436
+ batch_size=len(objs_without_pk), # Use actual batch size
437
+ )
438
+ for obj_without_pk, results in zip(
439
+ objs_without_pk, returned_columns
440
+ ):
441
+ for result, field in zip(results, opts.db_returning_fields):
442
+ setattr(obj_without_pk, field.attname, result)
443
+ obj_without_pk._state.adding = False
444
+ obj_without_pk._state.db = self.db
488
445
 
489
446
  # Step 3: Update original objects with generated PKs and state
490
447
  pk_field_name = child_model._meta.pk.name
@@ -537,15 +494,19 @@ class HookQuerySet(models.QuerySet):
537
494
  value = getattr(source_obj, field.name, None)
538
495
  if value is not None:
539
496
  setattr(child_obj, field.name, value)
540
-
497
+
541
498
  # Set parent links for MTI
542
499
  for parent_model, parent_instance in parent_instances.items():
543
500
  parent_link = child_model._meta.get_ancestor_link(parent_model)
544
501
  if parent_link:
545
502
  # Set both the foreign key value (the ID) and the object reference
546
503
  # This follows Django's pattern in _set_pk_val
547
- setattr(child_obj, parent_link.attname, parent_instance.pk) # Set the foreign key value
548
- setattr(child_obj, parent_link.name, parent_instance) # Set the object reference
504
+ setattr(
505
+ child_obj, parent_link.attname, parent_instance.pk
506
+ ) # Set the foreign key value
507
+ setattr(
508
+ child_obj, parent_link.name, parent_instance
509
+ ) # Set the object reference
549
510
 
550
511
  # Handle auto_now_add and auto_now fields like Django does
551
512
  for field in child_model._meta.local_fields:
@@ -558,4 +519,4 @@ class HookQuerySet(models.QuerySet):
558
519
  elif hasattr(field, "auto_now") and field.auto_now:
559
520
  field.pre_save(child_obj, add=True)
560
521
 
561
- return child_obj
522
+ return child_obj
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "django-bulk-hooks"
3
- version = "0.1.173"
3
+ version = "0.1.176"
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"