django-bulk-hooks 0.2.51__tar.gz → 0.2.53__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.2.51 → django_bulk_hooks-0.2.53}/PKG-INFO +1 -1
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/bulk_executor.py +17 -28
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/mti_handler.py +12 -13
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/pyproject.toml +1 -1
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/LICENSE +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/README.md +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/__init__.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/changeset.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/conditions.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/constants.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/context.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/decorators.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/dispatcher.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/enums.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/factory.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/handler.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/helpers.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/manager.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/models.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/__init__.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/analyzer.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/coordinator.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/field_utils.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/mti_plans.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/record_classifier.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/queryset.py +0 -0
- {django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/registry.py +0 -0
{django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/bulk_executor.py
RENAMED
|
@@ -261,57 +261,46 @@ class BulkExecutor:
|
|
|
261
261
|
parent_instances_map[orig_obj_id] = {}
|
|
262
262
|
parent_instances_map[orig_obj_id][parent_level.model_class] = parent_obj
|
|
263
263
|
|
|
264
|
-
# Step 2: Add parent links to child objects and set PKs
|
|
264
|
+
# Step 2: Add parent links to child objects and set PKs appropriately
|
|
265
265
|
for child_obj, orig_obj in zip(plan.child_objects, plan.original_objects):
|
|
266
266
|
parent_instances = parent_instances_map.get(id(orig_obj), {})
|
|
267
267
|
|
|
268
|
-
# Set parent links
|
|
268
|
+
# Set parent links and PKs for all objects (since in MTI, child PK = parent PK)
|
|
269
269
|
for parent_model, parent_instance in parent_instances.items():
|
|
270
270
|
parent_link = plan.child_model._meta.get_ancestor_link(parent_model)
|
|
271
271
|
if parent_link:
|
|
272
|
-
|
|
272
|
+
parent_pk = parent_instance.pk
|
|
273
|
+
setattr(child_obj, parent_link.attname, parent_pk)
|
|
273
274
|
setattr(child_obj, parent_link.name, parent_instance)
|
|
274
|
-
#
|
|
275
|
-
|
|
275
|
+
# In MTI, the child PK IS the parent link
|
|
276
|
+
child_obj.pk = parent_pk
|
|
277
|
+
child_obj.id = parent_pk
|
|
276
278
|
else:
|
|
277
279
|
logger.warning(f"No parent link found for {parent_model} in {plan.child_model}")
|
|
278
280
|
|
|
279
|
-
# For existing records in upsert, ensure PK is set on child object
|
|
280
|
-
if id(orig_obj) in plan.existing_record_ids:
|
|
281
|
-
pk_value = getattr(orig_obj, "pk", None)
|
|
282
|
-
if pk_value:
|
|
283
|
-
child_obj.pk = pk_value
|
|
284
|
-
child_obj.id = pk_value
|
|
285
|
-
else:
|
|
286
|
-
# If no PK on original object, this is a new record, don't set PK
|
|
287
|
-
logger.info(f"New record {orig_obj} - not setting PK on child object")
|
|
288
|
-
|
|
289
281
|
# Step 3: Handle child objects
|
|
290
282
|
# Note: We can't use bulk_create on child MTI models, so we use _batched_insert for new records
|
|
291
283
|
# and bulk_update for existing records
|
|
292
284
|
base_qs = BaseQuerySet(model=plan.child_model, using=self.queryset.db)
|
|
293
|
-
|
|
294
|
-
# For MTI child objects, we need to
|
|
295
|
-
# In MTI, child objects get PKs from parent links, but we need to distinguish
|
|
296
|
-
# between truly new records and existing records for upsert operations
|
|
285
|
+
|
|
286
|
+
# For MTI child objects, we need to distinguish between truly new records and existing records for upsert operations
|
|
297
287
|
objs_without_pk, objs_with_pk = [], []
|
|
298
|
-
|
|
288
|
+
|
|
299
289
|
# Check which CHILD records actually exist in the child table
|
|
300
|
-
# This is separate from checking parent existence
|
|
301
290
|
if plan.update_conflicts:
|
|
302
|
-
#
|
|
303
|
-
|
|
291
|
+
# For upsert, check which child records exist based on the parent PKs
|
|
292
|
+
parent_pks_to_check = []
|
|
304
293
|
for child_obj in plan.child_objects:
|
|
305
294
|
child_pk = getattr(child_obj, plan.child_model._meta.pk.attname, None)
|
|
306
295
|
if child_pk:
|
|
307
|
-
|
|
308
|
-
|
|
296
|
+
parent_pks_to_check.append(child_pk)
|
|
297
|
+
|
|
309
298
|
existing_child_pks = set()
|
|
310
|
-
if
|
|
299
|
+
if parent_pks_to_check:
|
|
311
300
|
existing_child_pks = set(
|
|
312
|
-
base_qs.filter(pk__in=
|
|
301
|
+
base_qs.filter(pk__in=parent_pks_to_check).values_list('pk', flat=True)
|
|
313
302
|
)
|
|
314
|
-
|
|
303
|
+
|
|
315
304
|
# Split based on whether child record exists
|
|
316
305
|
for child_obj in plan.child_objects:
|
|
317
306
|
child_pk = getattr(child_obj, plan.child_model._meta.pk.attname, None)
|
{django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/mti_handler.py
RENAMED
|
@@ -121,26 +121,29 @@ class MTIHandler:
|
|
|
121
121
|
- If parent exists but child doesn't: creating child for existing parent → AFTER_UPDATE
|
|
122
122
|
- If neither exists: creating both parent and child → AFTER_CREATE
|
|
123
123
|
|
|
124
|
-
Therefore, we
|
|
125
|
-
|
|
124
|
+
Therefore, we find the model that contains all the unique fields, regardless
|
|
125
|
+
of whether it's the parent or child model.
|
|
126
126
|
|
|
127
127
|
Args:
|
|
128
128
|
unique_fields: List of field names forming the unique constraint
|
|
129
129
|
|
|
130
130
|
Returns:
|
|
131
|
-
Model class to query for existing records (
|
|
131
|
+
Model class to query for existing records (model containing unique fields)
|
|
132
132
|
"""
|
|
133
133
|
if not unique_fields:
|
|
134
134
|
return self.model_cls
|
|
135
135
|
|
|
136
136
|
inheritance_chain = self.get_inheritance_chain()
|
|
137
137
|
|
|
138
|
-
# For MTI models
|
|
139
|
-
# This ensures we check if the parent exists, which determines create vs update hooks
|
|
138
|
+
# For MTI models, find the model in the chain that contains ALL unique fields
|
|
140
139
|
if len(inheritance_chain) > 1:
|
|
141
|
-
|
|
140
|
+
# Walk through inheritance chain from child to parent
|
|
141
|
+
for model in reversed(inheritance_chain): # Start with child, end with root parent
|
|
142
|
+
model_field_names = {f.name for f in model._meta.local_fields}
|
|
143
|
+
if all(field in model_field_names for field in unique_fields):
|
|
144
|
+
return model
|
|
142
145
|
|
|
143
|
-
# For non-MTI models
|
|
146
|
+
# For non-MTI models or as fallback
|
|
144
147
|
return self.model_cls
|
|
145
148
|
|
|
146
149
|
# ==================== MTI BULK CREATE PLANNING ====================
|
|
@@ -190,12 +193,8 @@ class MTIHandler:
|
|
|
190
193
|
if existing_pks_map is None:
|
|
191
194
|
existing_pks_map = {}
|
|
192
195
|
|
|
193
|
-
#
|
|
194
|
-
|
|
195
|
-
for obj in objs:
|
|
196
|
-
if id(obj) in existing_pks_map:
|
|
197
|
-
obj.pk = existing_pks_map[id(obj)]
|
|
198
|
-
obj.id = existing_pks_map[id(obj)]
|
|
196
|
+
# For upsert operations, don't set PKs on source objects - let Django's bulk_create handle it
|
|
197
|
+
# The PKs will be set on the resulting objects after the bulk operation
|
|
199
198
|
|
|
200
199
|
# Build parent levels
|
|
201
200
|
parent_levels = self._build_parent_levels(
|
|
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
|
|
File without changes
|
{django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/__init__.py
RENAMED
|
File without changes
|
{django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/analyzer.py
RENAMED
|
File without changes
|
{django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/coordinator.py
RENAMED
|
File without changes
|
{django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/field_utils.py
RENAMED
|
File without changes
|
{django_bulk_hooks-0.2.51 → django_bulk_hooks-0.2.53}/django_bulk_hooks/operations/mti_plans.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|