django-bulk-hooks 0.1.171__tar.gz → 0.1.173__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.171 → django_bulk_hooks-0.1.173}/PKG-INFO +1 -1
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/queryset.py +119 -123
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/pyproject.toml +1 -1
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/LICENSE +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/README.md +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/__init__.py +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/conditions.py +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/constants.py +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/context.py +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/decorators.py +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/engine.py +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/enums.py +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/handler.py +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/manager.py +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/models.py +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/priority.py +0 -0
- {django_bulk_hooks-0.1.171 → django_bulk_hooks-0.1.173}/django_bulk_hooks/registry.py +0 -0
|
@@ -24,9 +24,8 @@ class HookQuerySet(models.QuerySet):
|
|
|
24
24
|
objs = list(self)
|
|
25
25
|
if not objs:
|
|
26
26
|
return 0
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
return len(objs)
|
|
27
|
+
# Call the base QuerySet implementation to avoid recursion
|
|
28
|
+
return super().bulk_delete(objs)
|
|
30
29
|
|
|
31
30
|
@transaction.atomic
|
|
32
31
|
def update(self, **kwargs):
|
|
@@ -34,28 +33,31 @@ class HookQuerySet(models.QuerySet):
|
|
|
34
33
|
if not instances:
|
|
35
34
|
return 0
|
|
36
35
|
|
|
36
|
+
model_cls = self.model
|
|
37
|
+
pks = [obj.pk for obj in instances]
|
|
38
|
+
|
|
39
|
+
# Load originals for hook comparison and ensure they match the order of instances
|
|
40
|
+
# Use the base manager to avoid recursion
|
|
41
|
+
original_map = {obj.pk: obj for obj in model_cls._base_manager.filter(pk__in=pks)}
|
|
42
|
+
originals = [original_map.get(obj.pk) for obj in instances]
|
|
43
|
+
|
|
37
44
|
# Apply field updates to instances
|
|
38
45
|
for obj in instances:
|
|
39
46
|
for field, value in kwargs.items():
|
|
40
47
|
setattr(obj, field, value)
|
|
41
48
|
|
|
42
|
-
#
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
# Run BEFORE_UPDATE hooks
|
|
50
|
+
ctx = HookContext(model_cls)
|
|
51
|
+
engine.run(model_cls, BEFORE_UPDATE, instances, originals, ctx=ctx)
|
|
45
52
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)
|
|
55
|
-
else:
|
|
56
|
-
# Use bulk_create for new objects
|
|
57
|
-
self.bulk_create([obj])
|
|
58
|
-
return obj
|
|
53
|
+
# Use Django's built-in update logic directly
|
|
54
|
+
# Call the base QuerySet implementation to avoid recursion
|
|
55
|
+
update_count = super().update(**kwargs)
|
|
56
|
+
|
|
57
|
+
# Run AFTER_UPDATE hooks
|
|
58
|
+
engine.run(model_cls, AFTER_UPDATE, instances, originals, ctx=ctx)
|
|
59
|
+
|
|
60
|
+
return update_count
|
|
59
61
|
|
|
60
62
|
@transaction.atomic
|
|
61
63
|
def bulk_create(
|
|
@@ -112,30 +114,35 @@ class HookQuerySet(models.QuerySet):
|
|
|
112
114
|
|
|
113
115
|
# Fire hooks before DB ops
|
|
114
116
|
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)}")
|
|
115
122
|
ctx = HookContext(model_cls)
|
|
116
123
|
if not bypass_validation:
|
|
124
|
+
print(f"DEBUG: Running VALIDATE_CREATE hooks")
|
|
117
125
|
engine.run(model_cls, VALIDATE_CREATE, objs, ctx=ctx)
|
|
126
|
+
print(f"DEBUG: Running BEFORE_CREATE hooks")
|
|
118
127
|
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}")
|
|
119
130
|
|
|
120
131
|
# For MTI models, we need to handle them specially
|
|
121
132
|
if is_mti:
|
|
122
133
|
# Use our MTI-specific logic
|
|
123
134
|
# Filter out custom parameters that Django's bulk_create doesn't accept
|
|
124
135
|
mti_kwargs = {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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,
|
|
130
141
|
}
|
|
131
142
|
# Remove custom hook kwargs if present in self.bulk_create signature
|
|
132
143
|
result = self._mti_bulk_create(
|
|
133
144
|
objs,
|
|
134
|
-
**{
|
|
135
|
-
k: v
|
|
136
|
-
for k, v in mti_kwargs.items()
|
|
137
|
-
if k not in ["bypass_hooks", "bypass_validation"]
|
|
138
|
-
},
|
|
145
|
+
**{k: v for k, v in mti_kwargs.items() if k not in ['bypass_hooks', 'bypass_validation']}
|
|
139
146
|
)
|
|
140
147
|
else:
|
|
141
148
|
# For single-table models, use Django's built-in bulk_create
|
|
@@ -144,7 +151,6 @@ class HookQuerySet(models.QuerySet):
|
|
|
144
151
|
|
|
145
152
|
# Use Django's original QuerySet to avoid recursive calls
|
|
146
153
|
from django.db.models import QuerySet
|
|
147
|
-
|
|
148
154
|
original_qs = QuerySet(model_cls, using=self.db)
|
|
149
155
|
result = original_qs.bulk_create(
|
|
150
156
|
objs,
|
|
@@ -157,19 +163,37 @@ class HookQuerySet(models.QuerySet):
|
|
|
157
163
|
|
|
158
164
|
# Fire AFTER_CREATE hooks
|
|
159
165
|
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)}")
|
|
160
170
|
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}")
|
|
161
173
|
|
|
162
174
|
return result
|
|
163
175
|
|
|
164
176
|
@transaction.atomic
|
|
165
|
-
def bulk_update(
|
|
166
|
-
self, objs, fields, bypass_hooks=False, bypass_validation=False, **kwargs
|
|
167
|
-
):
|
|
177
|
+
def bulk_update(self, objs, fields, bypass_hooks=False, bypass_validation=False, **kwargs):
|
|
168
178
|
"""
|
|
169
179
|
Bulk update objects in the database.
|
|
170
180
|
"""
|
|
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
|
+
|
|
171
191
|
model_cls = self.model
|
|
172
|
-
|
|
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
|
+
|
|
173
197
|
if not objs:
|
|
174
198
|
return []
|
|
175
199
|
|
|
@@ -183,9 +207,7 @@ class HookQuerySet(models.QuerySet):
|
|
|
183
207
|
# Use the base manager to avoid recursion
|
|
184
208
|
original_map = {
|
|
185
209
|
obj.pk: obj
|
|
186
|
-
for obj in model_cls._base_manager.filter(
|
|
187
|
-
pk__in=[obj.pk for obj in objs]
|
|
188
|
-
)
|
|
210
|
+
for obj in model_cls._base_manager.filter(pk__in=[obj.pk for obj in objs])
|
|
189
211
|
}
|
|
190
212
|
originals = [original_map.get(obj.pk) for obj in objs]
|
|
191
213
|
|
|
@@ -197,7 +219,12 @@ class HookQuerySet(models.QuerySet):
|
|
|
197
219
|
|
|
198
220
|
# Then run business logic hooks
|
|
199
221
|
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]}")
|
|
200
225
|
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}")
|
|
201
228
|
|
|
202
229
|
# Automatically detect fields that were modified during BEFORE_UPDATE hooks
|
|
203
230
|
modified_fields = self._detect_modified_fields(objs, originals)
|
|
@@ -212,15 +239,15 @@ class HookQuerySet(models.QuerySet):
|
|
|
212
239
|
|
|
213
240
|
# Call the base implementation to avoid re-triggering this method
|
|
214
241
|
# Filter out custom parameters that Django's bulk_update doesn't accept
|
|
215
|
-
django_kwargs = {
|
|
216
|
-
k: v
|
|
217
|
-
for k, v in kwargs.items()
|
|
218
|
-
if k not in ["bypass_hooks", "bypass_validation"]
|
|
219
|
-
}
|
|
242
|
+
django_kwargs = {k: v for k, v in kwargs.items() if k not in ['bypass_hooks', 'bypass_validation']}
|
|
220
243
|
super().bulk_update(chunk, fields, **django_kwargs)
|
|
221
244
|
|
|
222
245
|
if not bypass_hooks:
|
|
246
|
+
print(f"DEBUG: Firing AFTER_UPDATE hooks for {model_cls}")
|
|
247
|
+
print(f"DEBUG: Number of objects: {len(objs)}")
|
|
223
248
|
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}")
|
|
224
251
|
|
|
225
252
|
return objs
|
|
226
253
|
|
|
@@ -250,23 +277,9 @@ class HookQuerySet(models.QuerySet):
|
|
|
250
277
|
|
|
251
278
|
pks = [obj.pk for obj in objs if obj.pk is not None]
|
|
252
279
|
|
|
253
|
-
#
|
|
254
|
-
#
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
base_qs = QuerySet(model_cls, using=self.db)
|
|
258
|
-
|
|
259
|
-
# Delete in batches if batch_size is specified
|
|
260
|
-
if batch_size:
|
|
261
|
-
for i in range(0, len(objs), batch_size):
|
|
262
|
-
batch = objs[i : i + batch_size]
|
|
263
|
-
batch_pks = [obj.pk for obj in batch if obj.pk is not None]
|
|
264
|
-
if batch_pks:
|
|
265
|
-
base_qs.filter(pk__in=batch_pks).delete()
|
|
266
|
-
else:
|
|
267
|
-
# Delete all at once
|
|
268
|
-
if pks:
|
|
269
|
-
base_qs.filter(pk__in=pks).delete()
|
|
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)
|
|
270
283
|
|
|
271
284
|
if not bypass_hooks:
|
|
272
285
|
engine.run(model_cls, AFTER_DELETE, objs, ctx=ctx)
|
|
@@ -337,11 +350,7 @@ class HookQuerySet(models.QuerySet):
|
|
|
337
350
|
Sets auto_now_add/auto_now fields for each model in the chain.
|
|
338
351
|
"""
|
|
339
352
|
# Remove custom hook kwargs before passing to Django internals
|
|
340
|
-
django_kwargs = {
|
|
341
|
-
k: v
|
|
342
|
-
for k, v in kwargs.items()
|
|
343
|
-
if k not in ["bypass_hooks", "bypass_validation"]
|
|
344
|
-
}
|
|
353
|
+
django_kwargs = {k: v for k, v in kwargs.items() if k not in ['bypass_hooks', 'bypass_validation']}
|
|
345
354
|
if inheritance_chain is None:
|
|
346
355
|
inheritance_chain = self._get_inheritance_chain()
|
|
347
356
|
|
|
@@ -374,9 +383,9 @@ class HookQuerySet(models.QuerySet):
|
|
|
374
383
|
|
|
375
384
|
# Step 1: Do O(n) normal inserts into parent tables to get primary keys back
|
|
376
385
|
# Get bypass_hooks from kwargs
|
|
377
|
-
bypass_hooks = kwargs.get(
|
|
378
|
-
bypass_validation = kwargs.get(
|
|
379
|
-
|
|
386
|
+
bypass_hooks = kwargs.get('bypass_hooks', False)
|
|
387
|
+
bypass_validation = kwargs.get('bypass_validation', False)
|
|
388
|
+
|
|
380
389
|
for obj in batch:
|
|
381
390
|
parent_instances = {}
|
|
382
391
|
current_parent = None
|
|
@@ -384,35 +393,32 @@ class HookQuerySet(models.QuerySet):
|
|
|
384
393
|
parent_obj = self._create_parent_instance(
|
|
385
394
|
obj, model_class, current_parent
|
|
386
395
|
)
|
|
387
|
-
|
|
396
|
+
|
|
388
397
|
# Fire parent hooks if not bypassed
|
|
389
398
|
if not bypass_hooks:
|
|
390
399
|
ctx = HookContext(model_class)
|
|
391
400
|
if not bypass_validation:
|
|
392
401
|
engine.run(model_class, VALIDATE_CREATE, [parent_obj], ctx=ctx)
|
|
393
402
|
engine.run(model_class, BEFORE_CREATE, [parent_obj], ctx=ctx)
|
|
394
|
-
|
|
403
|
+
|
|
395
404
|
# Use Django's base manager to create the object and get PKs back
|
|
396
405
|
# This bypasses hooks and the MTI exception
|
|
397
406
|
field_values = {
|
|
398
407
|
field.name: getattr(parent_obj, field.name)
|
|
399
408
|
for field in model_class._meta.local_fields
|
|
400
|
-
if hasattr(parent_obj, field.name)
|
|
401
|
-
and getattr(parent_obj, field.name) is not None
|
|
409
|
+
if hasattr(parent_obj, field.name) and getattr(parent_obj, field.name) is not None
|
|
402
410
|
}
|
|
403
|
-
created_obj = model_class._base_manager.using(self.db).create(
|
|
404
|
-
|
|
405
|
-
)
|
|
406
|
-
|
|
411
|
+
created_obj = model_class._base_manager.using(self.db).create(**field_values)
|
|
412
|
+
|
|
407
413
|
# Update the parent_obj with the created object's PK
|
|
408
414
|
parent_obj.pk = created_obj.pk
|
|
409
415
|
parent_obj._state.adding = False
|
|
410
416
|
parent_obj._state.db = self.db
|
|
411
|
-
|
|
417
|
+
|
|
412
418
|
# Fire AFTER_CREATE hooks for parent
|
|
413
419
|
if not bypass_hooks:
|
|
414
420
|
engine.run(model_class, AFTER_CREATE, [parent_obj], ctx=ctx)
|
|
415
|
-
|
|
421
|
+
|
|
416
422
|
parent_instances[model_class] = parent_obj
|
|
417
423
|
current_parent = parent_obj
|
|
418
424
|
parent_objects_map[id(obj)] = parent_instances
|
|
@@ -430,10 +436,10 @@ class HookQuerySet(models.QuerySet):
|
|
|
430
436
|
if all_child_objects:
|
|
431
437
|
# Get the base manager's queryset
|
|
432
438
|
base_qs = child_model._base_manager.using(self.db)
|
|
433
|
-
|
|
439
|
+
|
|
434
440
|
# Use Django's exact approach: call _prepare_for_bulk_create then partition
|
|
435
441
|
base_qs._prepare_for_bulk_create(all_child_objects)
|
|
436
|
-
|
|
442
|
+
|
|
437
443
|
# Implement our own partition since itertools.partition might not be available
|
|
438
444
|
objs_without_pk, objs_with_pk = [], []
|
|
439
445
|
for obj in all_child_objects:
|
|
@@ -441,50 +447,44 @@ class HookQuerySet(models.QuerySet):
|
|
|
441
447
|
objs_with_pk.append(obj)
|
|
442
448
|
else:
|
|
443
449
|
objs_without_pk.append(obj)
|
|
444
|
-
|
|
450
|
+
|
|
445
451
|
# Use Django's internal _batched_insert method
|
|
446
452
|
opts = child_model._meta
|
|
447
453
|
# For child models in MTI, we need to include the foreign key to the parent
|
|
448
454
|
# but exclude the primary key since it's inherited
|
|
449
|
-
|
|
455
|
+
|
|
450
456
|
# Include all local fields except generated ones
|
|
451
457
|
# We need to include the foreign key to the parent (business_ptr)
|
|
452
458
|
fields = [f for f in opts.local_fields if not f.generated]
|
|
453
|
-
|
|
459
|
+
|
|
454
460
|
with transaction.atomic(using=self.db, savepoint=False):
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
objs_without_pk, returned_columns
|
|
483
|
-
):
|
|
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
|
|
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
|
|
488
488
|
|
|
489
489
|
# Step 3: Update original objects with generated PKs and state
|
|
490
490
|
pk_field_name = child_model._meta.pk.name
|
|
@@ -537,19 +537,15 @@ class HookQuerySet(models.QuerySet):
|
|
|
537
537
|
value = getattr(source_obj, field.name, None)
|
|
538
538
|
if value is not None:
|
|
539
539
|
setattr(child_obj, field.name, value)
|
|
540
|
-
|
|
540
|
+
|
|
541
541
|
# Set parent links for MTI
|
|
542
542
|
for parent_model, parent_instance in parent_instances.items():
|
|
543
543
|
parent_link = child_model._meta.get_ancestor_link(parent_model)
|
|
544
544
|
if parent_link:
|
|
545
545
|
# Set both the foreign key value (the ID) and the object reference
|
|
546
546
|
# This follows Django's pattern in _set_pk_val
|
|
547
|
-
setattr(
|
|
548
|
-
|
|
549
|
-
) # Set the foreign key value
|
|
550
|
-
setattr(
|
|
551
|
-
child_obj, parent_link.name, parent_instance
|
|
552
|
-
) # Set the object reference
|
|
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
|
|
553
549
|
|
|
554
550
|
# Handle auto_now_add and auto_now fields like Django does
|
|
555
551
|
for field in child_model._meta.local_fields:
|
|
@@ -562,4 +558,4 @@ class HookQuerySet(models.QuerySet):
|
|
|
562
558
|
elif hasattr(field, "auto_now") and field.auto_now:
|
|
563
559
|
field.pre_save(child_obj, add=True)
|
|
564
560
|
|
|
565
|
-
return child_obj
|
|
561
|
+
return child_obj
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "django-bulk-hooks"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.173"
|
|
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
|