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

@@ -22,185 +22,6 @@ class BulkHookManager(models.Manager):
22
22
  def get_queryset(self):
23
23
  return HookQuerySet(self.model, using=self._db)
24
24
 
25
- def _has_multi_table_inheritance(self, model_cls):
26
- """
27
- Check if this model uses multi-table inheritance.
28
- """
29
- if not model_cls._meta.parents:
30
- return False
31
-
32
- # Check if any parent is not abstract
33
- for parent_model in model_cls._meta.parents.keys():
34
- if not parent_model._meta.abstract:
35
- return True
36
-
37
- return False
38
-
39
- def _get_base_model(self, model_cls):
40
- """
41
- Get the base model (first non-abstract parent or self).
42
- """
43
- base_model = model_cls
44
- while base_model._meta.parents:
45
- # Get the first non-abstract parent model
46
- for parent_model in base_model._meta.parents.keys():
47
- if not parent_model._meta.abstract:
48
- base_model = parent_model
49
- break
50
- else:
51
- # No non-abstract parents found, break the loop
52
- break
53
- return base_model
54
-
55
- def _extract_base_objects(self, objs, model_cls):
56
- """
57
- Extract base model objects from inherited objects.
58
- """
59
- base_model = self._get_base_model(model_cls)
60
- base_objects = []
61
-
62
- for obj in objs:
63
- base_obj = base_model()
64
- for field in base_model._meta.fields:
65
- # Skip ID field
66
- if field.name == 'id':
67
- continue
68
-
69
- # Safely copy field values
70
- try:
71
- if hasattr(obj, field.name):
72
- setattr(base_obj, field.name, getattr(obj, field.name))
73
- except (AttributeError, ValueError):
74
- # Skip fields that can't be copied
75
- continue
76
-
77
- base_objects.append(base_obj)
78
-
79
- return base_objects
80
-
81
- def _extract_child_objects(self, objs, model_cls):
82
- """
83
- Extract child model objects from inherited objects.
84
- """
85
- child_objects = []
86
-
87
- for obj in objs:
88
- child_obj = model_cls()
89
- child_obj.pk = obj.pk # Set the same PK as base
90
-
91
- # Copy only fields specific to this model
92
- for field in model_cls._meta.fields:
93
- # Skip ID field and fields that don't belong to this model
94
- if field.name == 'id':
95
- continue
96
-
97
- # Check if this field belongs to the current model
98
- # Use a safer way to check field ownership
99
- try:
100
- if hasattr(field, 'model') and field.model == model_cls:
101
- # This field belongs to the current model
102
- if hasattr(obj, field.name):
103
- setattr(child_obj, field.name, getattr(obj, field.name))
104
- except AttributeError:
105
- # Skip fields that don't have proper model reference
106
- continue
107
-
108
- child_objects.append(child_obj)
109
-
110
- return child_objects
111
-
112
- def _bulk_create_inherited(self, objs, **kwargs):
113
- """
114
- Handle bulk create for inherited models by handling each table separately.
115
- """
116
- if not objs:
117
- return []
118
-
119
- model_cls = self.model
120
- result = []
121
-
122
- # Group objects by their actual class
123
- objects_by_class = {}
124
- for obj in objs:
125
- obj_class = obj.__class__
126
- if obj_class not in objects_by_class:
127
- objects_by_class[obj_class] = []
128
- objects_by_class[obj_class].append(obj)
129
-
130
- for obj_class, class_objects in objects_by_class.items():
131
- try:
132
- # Check if this class has multi-table inheritance
133
- parent_models = [p for p in obj_class._meta.get_parent_list()
134
- if not p._meta.abstract]
135
-
136
- if not parent_models:
137
- # No inheritance, use standard bulk_create
138
- chunk_result = super(models.Manager, self).bulk_create(class_objects, **kwargs)
139
- result.extend(chunk_result)
140
- continue
141
-
142
- # Handle multi-table inheritance
143
- # Step 1: Bulk create base objects with hooks
144
- base_objects = self._extract_base_objects(class_objects, obj_class)
145
-
146
- # Use the model's manager with hooks
147
- base_model = self._get_base_model(obj_class)
148
-
149
- # Try to avoid recursion by using raw SQL or _base_manager
150
- try:
151
- if hasattr(base_model.objects, 'bulk_create'):
152
- # Use the base model's manager with hooks
153
- created_base = base_model.objects.bulk_create(base_objects, **kwargs)
154
- else:
155
- # Fallback to _base_manager
156
- created_base = base_model._base_manager.bulk_create(base_objects, **kwargs)
157
- except RecursionError:
158
- # If recursion error, use _base_manager directly
159
- created_base = base_model._base_manager.bulk_create(base_objects, **kwargs)
160
-
161
- # Step 2: Update original objects with base IDs
162
- for obj, base_obj in zip(class_objects, created_base):
163
- obj.pk = base_obj.pk
164
- obj._state.adding = False
165
-
166
- # Step 3: Bulk create child objects with hooks
167
- child_objects = self._extract_child_objects(class_objects, obj_class)
168
- if child_objects:
169
- # Use _base_manager to avoid recursion with custom managers
170
- try:
171
- obj_class._base_manager.bulk_create(child_objects, **kwargs)
172
- except RecursionError:
173
- # If recursion error, use individual saves
174
- for obj in child_objects:
175
- obj.save()
176
-
177
- result.extend(class_objects)
178
-
179
- except Exception as e:
180
- # Add debugging information
181
- import logging
182
- logger = logging.getLogger(__name__)
183
- logger.error(f"Error in _bulk_create_inherited for {obj_class}: {e}")
184
- logger.error(f"Model fields: {[f.name for f in obj_class._meta.fields]}")
185
- logger.error(f"Base model: {self._get_base_model(obj_class)}")
186
- logger.error(f"Base model manager: {self._get_base_model(obj_class).objects}")
187
-
188
- # If it's a recursion error, try a simpler approach
189
- if isinstance(e, RecursionError):
190
- logger.error("Recursion error detected, trying fallback approach")
191
- try:
192
- # Fallback: use individual saves
193
- for obj in class_objects:
194
- obj.save()
195
- result.extend(class_objects)
196
- continue
197
- except Exception as fallback_error:
198
- logger.error(f"Fallback approach also failed: {fallback_error}")
199
-
200
- raise
201
-
202
- return result
203
-
204
25
  @transaction.atomic
205
26
  def bulk_update(
206
27
  self, objs, fields, bypass_hooks=False, bypass_validation=False, **kwargs
@@ -295,9 +116,6 @@ class BulkHookManager(models.Manager):
295
116
  f"bulk_create expected instances of {model_cls.__name__}, but got {set(type(obj).__name__ for obj in objs)}"
296
117
  )
297
118
 
298
- # Check if this model uses multi-table inheritance
299
- has_multi_table_inheritance = self._has_multi_table_inheritance(model_cls)
300
-
301
119
  result = []
302
120
 
303
121
  if not bypass_hooks:
@@ -310,18 +128,9 @@ class BulkHookManager(models.Manager):
310
128
  # Then run business logic hooks
311
129
  engine.run(model_cls, BEFORE_CREATE, objs, ctx=ctx)
312
130
 
313
- # Perform bulk create in chunks
314
131
  for i in range(0, len(objs), self.CHUNK_SIZE):
315
132
  chunk = objs[i : i + self.CHUNK_SIZE]
316
-
317
- if has_multi_table_inheritance:
318
- # Use our multi-table bulk create
319
- created_chunk = self._bulk_create_inherited(chunk, **kwargs)
320
- else:
321
- # Use Django's standard bulk create
322
- created_chunk = super(models.Manager, self).bulk_create(chunk, **kwargs)
323
-
324
- result.extend(created_chunk)
133
+ result.extend(super(models.Manager, self).bulk_create(chunk, **kwargs))
325
134
 
326
135
  if not bypass_hooks:
327
136
  engine.run(model_cls, AFTER_CREATE, result, ctx=ctx)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: django-bulk-hooks
3
- Version: 0.1.110
3
+ Version: 0.1.111
4
4
  Summary: Hook-style hooks for Django bulk operations like bulk_create and bulk_update.
5
5
  License: MIT
6
6
  Keywords: django,bulk,hooks
@@ -6,12 +6,12 @@ django_bulk_hooks/decorators.py,sha256=tckDcxtOzKCbgvS9QydgeIAWTFDEl-ch3_Q--ruEG
6
6
  django_bulk_hooks/engine.py,sha256=3HbgV12JRYIy9IlygHPxZiHnFXj7EwzLyTuJNQeVIoI,1402
7
7
  django_bulk_hooks/enums.py,sha256=Zo8_tJzuzZ2IKfVc7gZ-0tWPT8q1QhqZbAyoh9ZVJbs,381
8
8
  django_bulk_hooks/handler.py,sha256=xZt8iNdYF-ACz-MnKMY0co6scWINU5V5wC1lyDn844k,4854
9
- django_bulk_hooks/manager.py,sha256=MzX9mMLbxAKMqYiKwFkieYn9EtxpLOUfA-S57co2q8I,15295
9
+ django_bulk_hooks/manager.py,sha256=JkhOw9XbEUt8VpunhUSP0z-NlazIFUWmAesj7H4ge8w,7148
10
10
  django_bulk_hooks/models.py,sha256=7RG7GrOdHXFjGVPV4FPRZVNMIHHW-hMCi6hn9LH_hVI,3331
11
11
  django_bulk_hooks/priority.py,sha256=HG_2D35nga68lBCZmSXTcplXrjFoRgZFRDOy4ROKonY,376
12
12
  django_bulk_hooks/queryset.py,sha256=iet4z-9SKhnresA4FBQbxx9rdYnoaOWbw9LUlGftlP0,1466
13
13
  django_bulk_hooks/registry.py,sha256=-mQBizJ06nz_tajZBinViKx_uP2Tbc1tIpTEMv7lwKA,705
14
- django_bulk_hooks-0.1.110.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
15
- django_bulk_hooks-0.1.110.dist-info/METADATA,sha256=P2a5pByPA96kdKHrURz7Rp1AGUHfV_c0JdbVo7Ost90,6951
16
- django_bulk_hooks-0.1.110.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
17
- django_bulk_hooks-0.1.110.dist-info/RECORD,,
14
+ django_bulk_hooks-0.1.111.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
15
+ django_bulk_hooks-0.1.111.dist-info/METADATA,sha256=eljgMdpOu6xv8oWYbEMeP0GM7oXy4NrVDHDlrAfpHP0,6951
16
+ django_bulk_hooks-0.1.111.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
17
+ django_bulk_hooks-0.1.111.dist-info/RECORD,,