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

@@ -1,150 +1,150 @@
1
- from django.db import models
2
-
3
- from django_bulk_hooks.queryset import HookQuerySet
4
-
5
-
6
- def _delegate_to_queryset(self, method_name, *args, **kwargs):
7
- """
8
- Generic delegation to queryset method.
9
-
10
- Args:
11
- method_name: Name of the method to call on the queryset
12
- *args, **kwargs: Arguments to pass to the method
13
-
14
- Returns:
15
- Result of the queryset method call
16
- """
17
- return getattr(self.get_queryset(), method_name)(*args, **kwargs)
18
-
19
-
20
- class BulkHookManager(models.Manager):
21
- """
22
- Manager that provides hook-aware bulk operations.
23
-
24
- This is a simple facade that returns HookQuerySet,
25
- delegating all bulk operations to it.
26
- """
27
-
28
- def get_queryset(self):
29
- """
30
- Return a HookQuerySet for this manager.
31
-
32
- This ensures all bulk operations go through the coordinator.
33
- """
34
- base_queryset = super().get_queryset()
35
-
36
- # If the base queryset is already a HookQuerySet, return it as-is
37
- if isinstance(base_queryset, HookQuerySet):
38
- return base_queryset
39
-
40
- # Otherwise, create a new HookQuerySet with the same parameters
41
- return HookQuerySet(
42
- model=base_queryset.model,
43
- query=base_queryset.query,
44
- using=base_queryset._db,
45
- hints=base_queryset._hints,
46
- )
47
-
48
- def bulk_create(
49
- self,
50
- objs,
51
- batch_size=None,
52
- ignore_conflicts=False,
53
- update_conflicts=False,
54
- update_fields=None,
55
- unique_fields=None,
56
- bypass_hooks=False,
57
- bypass_validation=False,
58
- **kwargs,
59
- ):
60
- """
61
- Delegate to QuerySet's bulk_create implementation.
62
- This follows Django's pattern where Manager methods call QuerySet methods.
63
- """
64
- return _delegate_to_queryset(
65
- self,
66
- "bulk_create",
67
- objs,
68
- batch_size=batch_size,
69
- ignore_conflicts=ignore_conflicts,
70
- update_conflicts=update_conflicts,
71
- update_fields=update_fields,
72
- unique_fields=unique_fields,
73
- bypass_hooks=bypass_hooks,
74
- bypass_validation=bypass_validation,
75
- **kwargs,
76
- )
77
-
78
- def bulk_update(
79
- self,
80
- objs,
81
- fields=None,
82
- bypass_hooks=False,
83
- bypass_validation=False,
84
- **kwargs,
85
- ):
86
- """
87
- Delegate to QuerySet's bulk_update implementation.
88
- This follows Django's pattern where Manager methods call QuerySet methods.
89
-
90
- Note: Parameters like unique_fields, update_conflicts, update_fields, and ignore_conflicts
91
- are not supported by bulk_update and will be ignored with a warning.
92
- These parameters are only available in bulk_create for UPSERT operations.
93
- """
94
- if fields is not None:
95
- kwargs["fields"] = fields
96
- return _delegate_to_queryset(
97
- self,
98
- "bulk_update",
99
- objs,
100
- bypass_hooks=bypass_hooks,
101
- bypass_validation=bypass_validation,
102
- **kwargs,
103
- )
104
-
105
- def bulk_delete(
106
- self,
107
- objs,
108
- batch_size=None,
109
- bypass_hooks=False,
110
- bypass_validation=False,
111
- **kwargs,
112
- ):
113
- """
114
- Delegate to QuerySet's bulk_delete implementation.
115
- This follows Django's pattern where Manager methods call QuerySet methods.
116
- """
117
- return _delegate_to_queryset(
118
- self,
119
- "bulk_delete",
120
- objs,
121
- batch_size=batch_size,
122
- bypass_hooks=bypass_hooks,
123
- bypass_validation=bypass_validation,
124
- **kwargs,
125
- )
126
-
127
- def delete(self):
128
- """
129
- Delegate to QuerySet's delete implementation.
130
- This follows Django's pattern where Manager methods call QuerySet methods.
131
- """
132
- return _delegate_to_queryset(self, "delete")
133
-
134
- def update(self, **kwargs):
135
- """
136
- Delegate to QuerySet's update implementation.
137
- This follows Django's pattern where Manager methods call QuerySet methods.
138
- """
139
- return _delegate_to_queryset(self, "update", **kwargs)
140
-
141
- def save(self, obj):
142
- """
143
- Save a single object using the appropriate bulk operation.
144
- """
145
- if obj.pk:
146
- # bulk_update now auto-detects changed fields
147
- self.bulk_update([obj])
148
- else:
149
- self.bulk_create([obj])
150
- return obj
1
+ from django.db import models
2
+
3
+ from django_bulk_hooks.queryset import HookQuerySet
4
+
5
+
6
+ def _delegate_to_queryset(self, method_name, *args, **kwargs):
7
+ """
8
+ Generic delegation to queryset method.
9
+
10
+ Args:
11
+ method_name: Name of the method to call on the queryset
12
+ *args, **kwargs: Arguments to pass to the method
13
+
14
+ Returns:
15
+ Result of the queryset method call
16
+ """
17
+ return getattr(self.get_queryset(), method_name)(*args, **kwargs)
18
+
19
+
20
+ class BulkHookManager(models.Manager):
21
+ """
22
+ Manager that provides hook-aware bulk operations.
23
+
24
+ This is a simple facade that returns HookQuerySet,
25
+ delegating all bulk operations to it.
26
+ """
27
+
28
+ def get_queryset(self):
29
+ """
30
+ Return a HookQuerySet for this manager.
31
+
32
+ This ensures all bulk operations go through the coordinator.
33
+ """
34
+ base_queryset = super().get_queryset()
35
+
36
+ # If the base queryset is already a HookQuerySet, return it as-is
37
+ if isinstance(base_queryset, HookQuerySet):
38
+ return base_queryset
39
+
40
+ # Otherwise, create a new HookQuerySet with the same parameters
41
+ return HookQuerySet(
42
+ model=base_queryset.model,
43
+ query=base_queryset.query,
44
+ using=base_queryset._db,
45
+ hints=base_queryset._hints,
46
+ )
47
+
48
+ def bulk_create(
49
+ self,
50
+ objs,
51
+ batch_size=None,
52
+ ignore_conflicts=False,
53
+ update_conflicts=False,
54
+ update_fields=None,
55
+ unique_fields=None,
56
+ bypass_hooks=False,
57
+ bypass_validation=False,
58
+ **kwargs,
59
+ ):
60
+ """
61
+ Delegate to QuerySet's bulk_create implementation.
62
+ This follows Django's pattern where Manager methods call QuerySet methods.
63
+ """
64
+ return _delegate_to_queryset(
65
+ self,
66
+ "bulk_create",
67
+ objs,
68
+ batch_size=batch_size,
69
+ ignore_conflicts=ignore_conflicts,
70
+ update_conflicts=update_conflicts,
71
+ update_fields=update_fields,
72
+ unique_fields=unique_fields,
73
+ bypass_hooks=bypass_hooks,
74
+ bypass_validation=bypass_validation,
75
+ **kwargs,
76
+ )
77
+
78
+ def bulk_update(
79
+ self,
80
+ objs,
81
+ fields=None,
82
+ bypass_hooks=False,
83
+ bypass_validation=False,
84
+ **kwargs,
85
+ ):
86
+ """
87
+ Delegate to QuerySet's bulk_update implementation.
88
+ This follows Django's pattern where Manager methods call QuerySet methods.
89
+
90
+ Note: Parameters like unique_fields, update_conflicts, update_fields, and ignore_conflicts
91
+ are not supported by bulk_update and will be ignored with a warning.
92
+ These parameters are only available in bulk_create for UPSERT operations.
93
+ """
94
+ if fields is not None:
95
+ kwargs["fields"] = fields
96
+ return _delegate_to_queryset(
97
+ self,
98
+ "bulk_update",
99
+ objs,
100
+ bypass_hooks=bypass_hooks,
101
+ bypass_validation=bypass_validation,
102
+ **kwargs,
103
+ )
104
+
105
+ def bulk_delete(
106
+ self,
107
+ objs,
108
+ batch_size=None,
109
+ bypass_hooks=False,
110
+ bypass_validation=False,
111
+ **kwargs,
112
+ ):
113
+ """
114
+ Delegate to QuerySet's bulk_delete implementation.
115
+ This follows Django's pattern where Manager methods call QuerySet methods.
116
+ """
117
+ return _delegate_to_queryset(
118
+ self,
119
+ "bulk_delete",
120
+ objs,
121
+ batch_size=batch_size,
122
+ bypass_hooks=bypass_hooks,
123
+ bypass_validation=bypass_validation,
124
+ **kwargs,
125
+ )
126
+
127
+ def delete(self):
128
+ """
129
+ Delegate to QuerySet's delete implementation.
130
+ This follows Django's pattern where Manager methods call QuerySet methods.
131
+ """
132
+ return _delegate_to_queryset(self, "delete")
133
+
134
+ def update(self, **kwargs):
135
+ """
136
+ Delegate to QuerySet's update implementation.
137
+ This follows Django's pattern where Manager methods call QuerySet methods.
138
+ """
139
+ return _delegate_to_queryset(self, "update", **kwargs)
140
+
141
+ def save(self, obj):
142
+ """
143
+ Save a single object using the appropriate bulk operation.
144
+ """
145
+ if obj.pk:
146
+ # bulk_update now auto-detects changed fields
147
+ self.bulk_update([obj])
148
+ else:
149
+ self.bulk_create([obj])
150
+ return obj
@@ -1,87 +1,74 @@
1
- import logging
2
-
3
- from django.db import models
4
-
5
- from django_bulk_hooks.manager import BulkHookManager
6
-
7
- logger = logging.getLogger(__name__)
8
-
9
-
10
- class TimestampMixin(models.Model):
11
- """Mixin providing standard created_at and updated_at timestamp fields."""
12
-
13
- created_at = models.DateTimeField(auto_now_add=True, help_text="When this record was created")
14
- updated_at = models.DateTimeField(auto_now=True, help_text="When this record was last updated")
15
-
16
- class Meta:
17
- abstract = True
18
-
19
-
20
- class HookModelMixin(TimestampMixin, models.Model):
21
- """Combined mixin providing timestamps and hook functionality."""
22
-
23
- objects = BulkHookManager()
24
-
25
- class Meta:
26
- abstract = True
27
-
28
- def clean(self, bypass_hooks=False):
29
- """
30
- Override clean() to hook validation hooks.
31
- This ensures that when Django calls clean() (like in admin forms),
32
- it hooks the VALIDATE_* hooks for validation only.
33
- """
34
- super().clean()
35
-
36
- # If bypass_hooks is True, skip validation hooks
37
- if bypass_hooks:
38
- return
39
-
40
- # Delegate to coordinator (consistent with save/delete)
41
- is_create = self.pk is None
42
- self.__class__.objects.get_queryset().coordinator.clean(
43
- [self], is_create=is_create,
44
- )
45
-
46
- def save(self, *args, bypass_hooks=False, **kwargs):
47
- """
48
- Save the model instance.
49
-
50
- Delegates to bulk_create/bulk_update which handle all hook logic
51
- including MTI parent hooks.
52
- """
53
- if bypass_hooks:
54
- # Use super().save() to call Django's default save without our hook logic
55
- return super().save(*args, **kwargs)
56
-
57
- is_create = self.pk is None
58
-
59
- if is_create:
60
- # Delegate to bulk_create which handles all hook logic
61
- result = self.__class__.objects.bulk_create([self])
62
- return result[0] if result else self
63
- # Delegate to bulk_update which handles all hook logic
64
- update_fields = kwargs.get("update_fields")
65
- if update_fields is None:
66
- # Update all non-auto fields
67
- update_fields = [
68
- f.name
69
- for f in self.__class__._meta.fields
70
- if not f.auto_created and f.name != "id"
71
- ]
72
- self.__class__.objects.bulk_update([self], update_fields)
73
- return self
74
-
75
- def delete(self, *args, bypass_hooks=False, **kwargs):
76
- """
77
- Delete the model instance.
78
-
79
- Delegates to bulk_delete which handles all hook logic
80
- including MTI parent hooks.
81
- """
82
- if bypass_hooks:
83
- # Use super().delete() to call Django's default delete without our hook logic
84
- return super().delete(*args, **kwargs)
85
-
86
- # Delegate to bulk_delete (handles both MTI and non-MTI)
87
- return self.__class__.objects.filter(pk=self.pk).delete()
1
+ import logging
2
+
3
+ from django.db import models
4
+
5
+ from django_bulk_hooks.manager import BulkHookManager
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ class HookModelMixin(models.Model):
11
+ """Mixin providing hook functionality."""
12
+
13
+ objects = BulkHookManager()
14
+
15
+ class Meta:
16
+ abstract = True
17
+
18
+ def clean(self, bypass_hooks=False):
19
+ """
20
+ Override clean() to hook validation hooks.
21
+ This ensures that when Django calls clean() (like in admin forms),
22
+ it hooks the VALIDATE_* hooks for validation only.
23
+ """
24
+ super().clean()
25
+
26
+ # If bypass_hooks is True, skip validation hooks
27
+ if bypass_hooks:
28
+ return
29
+
30
+ # Delegate to coordinator (consistent with save/delete)
31
+ is_create = self.pk is None
32
+ self.__class__.objects.get_queryset().coordinator.clean(
33
+ [self],
34
+ is_create=is_create,
35
+ )
36
+
37
+ def save(self, *args, bypass_hooks=False, **kwargs):
38
+ """
39
+ Save the model instance.
40
+
41
+ Delegates to bulk_create/bulk_update which handle all hook logic
42
+ including MTI parent hooks.
43
+ """
44
+ if bypass_hooks:
45
+ # Use super().save() to call Django's default save without our hook logic
46
+ return super().save(*args, **kwargs)
47
+
48
+ is_create = self.pk is None
49
+
50
+ if is_create:
51
+ # Delegate to bulk_create which handles all hook logic
52
+ result = self.__class__.objects.bulk_create([self])
53
+ return result[0] if result else self
54
+ # Delegate to bulk_update which handles all hook logic
55
+ update_fields = kwargs.get("update_fields")
56
+ if update_fields is None:
57
+ # Update all non-auto fields
58
+ update_fields = [f.name for f in self.__class__._meta.fields if not f.auto_created and f.name != "id"]
59
+ self.__class__.objects.bulk_update([self], update_fields)
60
+ return self
61
+
62
+ def delete(self, *args, bypass_hooks=False, **kwargs):
63
+ """
64
+ Delete the model instance.
65
+
66
+ Delegates to bulk_delete which handles all hook logic
67
+ including MTI parent hooks.
68
+ """
69
+ if bypass_hooks:
70
+ # Use super().delete() to call Django's default delete without our hook logic
71
+ return super().delete(*args, **kwargs)
72
+
73
+ # Delegate to bulk_delete (handles both MTI and non-MTI)
74
+ return self.__class__.objects.filter(pk=self.pk).delete()