django-bulk-hooks 0.1.188__tar.gz → 0.1.190__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.188 → django_bulk_hooks-0.1.190}/PKG-INFO +8 -3
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/README.md +7 -2
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/manager.py +48 -3
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/queryset.py +29 -5
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/pyproject.toml +1 -1
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/LICENSE +0 -0
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/__init__.py +0 -0
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/conditions.py +0 -0
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/constants.py +0 -0
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/context.py +0 -0
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/decorators.py +0 -0
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/engine.py +0 -0
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/enums.py +0 -0
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/handler.py +0 -0
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/models.py +0 -0
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/priority.py +0 -0
- {django_bulk_hooks-0.1.188 → django_bulk_hooks-0.1.190}/django_bulk_hooks/registry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: django-bulk-hooks
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.190
|
|
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
|
|
@@ -202,15 +202,20 @@ reordered = [account3, account1, account2] # IDs: 3, 1, 2
|
|
|
202
202
|
LoanAccount.objects.bulk_update(reordered, ['balance'])
|
|
203
203
|
```
|
|
204
204
|
|
|
205
|
-
## 🧩 Integration with
|
|
205
|
+
## 🧩 Integration with Other Managers
|
|
206
206
|
|
|
207
|
-
You can extend from `BulkHookManager` to
|
|
207
|
+
You can extend from `BulkHookManager` to work with other manager classes. The manager uses a cooperative approach that dynamically injects bulk hook functionality into any queryset, ensuring compatibility with other managers.
|
|
208
208
|
|
|
209
209
|
```python
|
|
210
|
+
from django_bulk_hooks.manager import BulkHookManager
|
|
211
|
+
from queryable_properties.managers import QueryablePropertiesManager
|
|
212
|
+
|
|
210
213
|
class MyManager(BulkHookManager, QueryablePropertiesManager):
|
|
211
214
|
pass
|
|
212
215
|
```
|
|
213
216
|
|
|
217
|
+
This approach uses the industry-standard injection pattern, similar to how `QueryablePropertiesManager` works, ensuring both functionalities work seamlessly together without any framework-specific knowledge.
|
|
218
|
+
|
|
214
219
|
## 📝 License
|
|
215
220
|
|
|
216
221
|
MIT © 2024 Augend / Konrad Beck
|
|
@@ -183,15 +183,20 @@ reordered = [account3, account1, account2] # IDs: 3, 1, 2
|
|
|
183
183
|
LoanAccount.objects.bulk_update(reordered, ['balance'])
|
|
184
184
|
```
|
|
185
185
|
|
|
186
|
-
## 🧩 Integration with
|
|
186
|
+
## 🧩 Integration with Other Managers
|
|
187
187
|
|
|
188
|
-
You can extend from `BulkHookManager` to
|
|
188
|
+
You can extend from `BulkHookManager` to work with other manager classes. The manager uses a cooperative approach that dynamically injects bulk hook functionality into any queryset, ensuring compatibility with other managers.
|
|
189
189
|
|
|
190
190
|
```python
|
|
191
|
+
from django_bulk_hooks.manager import BulkHookManager
|
|
192
|
+
from queryable_properties.managers import QueryablePropertiesManager
|
|
193
|
+
|
|
191
194
|
class MyManager(BulkHookManager, QueryablePropertiesManager):
|
|
192
195
|
pass
|
|
193
196
|
```
|
|
194
197
|
|
|
198
|
+
This approach uses the industry-standard injection pattern, similar to how `QueryablePropertiesManager` works, ensuring both functionalities work seamlessly together without any framework-specific knowledge.
|
|
199
|
+
|
|
195
200
|
## 📝 License
|
|
196
201
|
|
|
197
202
|
MIT © 2024 Augend / Konrad Beck
|
|
@@ -1,12 +1,57 @@
|
|
|
1
1
|
from django.db import models
|
|
2
2
|
|
|
3
|
-
from django_bulk_hooks.queryset import HookQuerySet
|
|
3
|
+
from django_bulk_hooks.queryset import HookQuerySet, HookQuerySetMixin
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def inject_bulk_hook_behavior(queryset):
|
|
7
|
+
"""
|
|
8
|
+
Dynamically inject bulk hook behavior into any queryset.
|
|
9
|
+
This follows the industry-standard pattern for cooperative queryset extensions.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
queryset: Any Django QuerySet instance
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
A new queryset instance with bulk hook functionality added
|
|
16
|
+
"""
|
|
17
|
+
if isinstance(queryset, HookQuerySetMixin):
|
|
18
|
+
# Already has hook functionality, return as-is
|
|
19
|
+
return queryset
|
|
20
|
+
|
|
21
|
+
# Create a new class that inherits from both HookQuerySetMixin and the queryset's class
|
|
22
|
+
HookedQuerySetClass = type(
|
|
23
|
+
"HookedQuerySet",
|
|
24
|
+
(HookQuerySetMixin, queryset.__class__),
|
|
25
|
+
{
|
|
26
|
+
'__module__': 'django_bulk_hooks.queryset',
|
|
27
|
+
'__doc__': f'Dynamically created queryset with bulk hook functionality for {queryset.__class__.__name__}'
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Create a new instance with the same parameters
|
|
32
|
+
new_queryset = HookedQuerySetClass(
|
|
33
|
+
model=queryset.model,
|
|
34
|
+
query=queryset.query,
|
|
35
|
+
using=queryset._db,
|
|
36
|
+
hints=queryset._hints
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Copy any additional attributes that might be important
|
|
40
|
+
for attr, value in queryset.__dict__.items():
|
|
41
|
+
if not hasattr(new_queryset, attr):
|
|
42
|
+
setattr(new_queryset, attr, value)
|
|
43
|
+
|
|
44
|
+
return new_queryset
|
|
4
45
|
|
|
5
46
|
|
|
6
47
|
class BulkHookManager(models.Manager):
|
|
7
48
|
def get_queryset(self):
|
|
8
|
-
|
|
9
|
-
|
|
49
|
+
# Use super().get_queryset() to let Django and MRO build the queryset
|
|
50
|
+
# This ensures cooperation with other managers
|
|
51
|
+
base_queryset = super().get_queryset()
|
|
52
|
+
|
|
53
|
+
# Inject our bulk hook behavior into the queryset
|
|
54
|
+
return inject_bulk_hook_behavior(base_queryset)
|
|
10
55
|
|
|
11
56
|
def bulk_create(
|
|
12
57
|
self,
|
|
@@ -17,7 +17,12 @@ from django_bulk_hooks.context import HookContext
|
|
|
17
17
|
from django.db.models import When, Value, Case
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
class
|
|
20
|
+
class HookQuerySetMixin:
|
|
21
|
+
"""
|
|
22
|
+
A mixin that provides bulk hook functionality to any QuerySet.
|
|
23
|
+
This can be dynamically injected into querysets from other managers.
|
|
24
|
+
"""
|
|
25
|
+
|
|
21
26
|
@transaction.atomic
|
|
22
27
|
def delete(self):
|
|
23
28
|
objs = list(self)
|
|
@@ -637,10 +642,16 @@ class HookQuerySet(models.QuerySet):
|
|
|
637
642
|
# If objects have pk set but are not loaded from DB, use those PKs
|
|
638
643
|
root_pks = []
|
|
639
644
|
for obj in batch:
|
|
640
|
-
|
|
641
|
-
|
|
645
|
+
# Check both pk and id attributes
|
|
646
|
+
pk_value = getattr(obj, 'pk', None)
|
|
647
|
+
if pk_value is None:
|
|
648
|
+
pk_value = getattr(obj, 'id', None)
|
|
649
|
+
|
|
650
|
+
if pk_value is not None:
|
|
651
|
+
root_pks.append(pk_value)
|
|
652
|
+
print(f"Found PK {pk_value} for object {obj}")
|
|
642
653
|
else:
|
|
643
|
-
print(f"WARNING: Object {obj} has no primary key")
|
|
654
|
+
print(f"WARNING: Object {obj} has no primary key (pk={getattr(obj, 'pk', None)}, id={getattr(obj, 'id', None)})")
|
|
644
655
|
continue
|
|
645
656
|
|
|
646
657
|
print(f"Root PKs to update: {root_pks}")
|
|
@@ -703,7 +714,12 @@ class HookQuerySet(models.QuerySet):
|
|
|
703
714
|
|
|
704
715
|
print(f"Building CASE statement for field: {field_name}")
|
|
705
716
|
for pk, obj in zip(pks, batch):
|
|
706
|
-
|
|
717
|
+
# Check both pk and id attributes for the object
|
|
718
|
+
obj_pk = getattr(obj, 'pk', None)
|
|
719
|
+
if obj_pk is None:
|
|
720
|
+
obj_pk = getattr(obj, 'id', None)
|
|
721
|
+
|
|
722
|
+
if obj_pk is None:
|
|
707
723
|
continue
|
|
708
724
|
value = getattr(obj, field_name)
|
|
709
725
|
print(f" PK {pk}: {field_name} = {value}")
|
|
@@ -727,3 +743,11 @@ class HookQuerySet(models.QuerySet):
|
|
|
727
743
|
|
|
728
744
|
print(f"Batch total updated: {total_updated}")
|
|
729
745
|
return total_updated
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
class HookQuerySet(HookQuerySetMixin, models.QuerySet):
|
|
749
|
+
"""
|
|
750
|
+
A QuerySet that provides bulk hook functionality.
|
|
751
|
+
This is the traditional approach for backward compatibility.
|
|
752
|
+
"""
|
|
753
|
+
pass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "django-bulk-hooks"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.190"
|
|
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
|