django-bulk-hooks 0.2.60__py3-none-any.whl → 0.2.62__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,99 +1,103 @@
1
- """
2
- MTI operation plans - Data structures for multi-table inheritance operations.
3
-
4
- These are pure data structures returned by MTIHandler to be executed by BulkExecutor.
5
- This separates planning (logic) from execution (database operations).
6
- """
7
-
8
- from dataclasses import dataclass
9
- from dataclasses import field
10
- from typing import Any
11
-
12
-
13
- @dataclass
14
- class ParentLevel:
15
- """
16
- Represents one level in the parent hierarchy for MTI bulk create.
17
-
18
- Attributes:
19
- model_class: The parent model class for this level
20
- objects: List of parent instances to create
21
- original_object_map: Maps parent instance id() -> original object id()
22
- update_conflicts: Whether to enable UPSERT for this level
23
- unique_fields: Fields for conflict detection (if update_conflicts=True)
24
- update_fields: Fields to update on conflict (if update_conflicts=True)
25
- """
26
-
27
- model_class: Any
28
- objects: list[Any]
29
- original_object_map: dict[int, int] = field(default_factory=dict)
30
- update_conflicts: bool = False
31
- unique_fields: list[str] = field(default_factory=list)
32
- update_fields: list[str] = field(default_factory=list)
33
-
34
-
35
- @dataclass
36
- class MTICreatePlan:
37
- """
38
- Plan for executing bulk_create on an MTI model.
39
-
40
- This plan describes WHAT to create, not HOW to create it.
41
- The executor is responsible for executing this plan.
42
-
43
- Attributes:
44
- inheritance_chain: List of model classes from root to child
45
- parent_levels: List of ParentLevel objects, one per parent model
46
- child_objects: List of child instances to create (not yet with parent links)
47
- child_model: The child model class
48
- original_objects: Original objects provided by user
49
- batch_size: Batch size for operations
50
- existing_record_ids: Set of id() of original objects that represent existing DB records
51
- update_conflicts: Whether this is an upsert operation
52
- unique_fields: Fields used for conflict detection
53
- update_fields: Fields to update on conflict
54
- """
55
-
56
- inheritance_chain: list[Any]
57
- parent_levels: list[ParentLevel]
58
- child_objects: list[Any]
59
- child_model: Any
60
- original_objects: list[Any]
61
- batch_size: int = None
62
- existing_record_ids: set = field(default_factory=set)
63
- update_conflicts: bool = False
64
- unique_fields: list[str] = field(default_factory=list)
65
- update_fields: list[str] = field(default_factory=list)
66
-
67
-
68
- @dataclass
69
- class ModelFieldGroup:
70
- """
71
- Represents fields to update for one model in the inheritance chain.
72
-
73
- Attributes:
74
- model_class: The model class
75
- fields: List of field names to update on this model
76
- filter_field: Field to use for filtering (e.g., 'pk' or parent link attname)
77
- """
78
-
79
- model_class: Any
80
- fields: list[str]
81
- filter_field: str = "pk"
82
-
83
-
84
- @dataclass
85
- class MTIUpdatePlan:
86
- """
87
- Plan for executing bulk_update on an MTI model.
88
-
89
- Attributes:
90
- inheritance_chain: List of model classes from root to child
91
- field_groups: List of ModelFieldGroup objects
92
- objects: Objects to update
93
- batch_size: Batch size for operations
94
- """
95
-
96
- inheritance_chain: list[Any]
97
- field_groups: list[ModelFieldGroup]
98
- objects: list[Any]
99
- batch_size: int = None
1
+ """
2
+ MTI operation plans - Data structures for multi-table inheritance operations.
3
+
4
+ These are pure data structures returned by MTIHandler to be executed by BulkExecutor.
5
+ This separates planning (logic) from execution (database operations).
6
+ """
7
+
8
+ from dataclasses import dataclass
9
+ from dataclasses import field
10
+ from typing import Any
11
+
12
+
13
+ @dataclass
14
+ class ParentLevel:
15
+ """
16
+ Represents one level in the parent hierarchy for MTI bulk create.
17
+
18
+ Attributes:
19
+ model_class: The parent model class for this level
20
+ objects: List of parent instances to create
21
+ original_object_map: Maps parent instance id() -> original object id()
22
+ update_conflicts: Whether to enable UPSERT for this level
23
+ unique_fields: Fields for conflict detection (if update_conflicts=True)
24
+ update_fields: Fields to update on conflict (if update_conflicts=True)
25
+ """
26
+
27
+ model_class: Any
28
+ objects: list[Any]
29
+ original_object_map: dict[int, int] = field(default_factory=dict)
30
+ update_conflicts: bool = False
31
+ unique_fields: list[str] = field(default_factory=list)
32
+ update_fields: list[str] = field(default_factory=list)
33
+
34
+
35
+ @dataclass
36
+ class MTICreatePlan:
37
+ """
38
+ Plan for executing bulk_create on an MTI model.
39
+
40
+ This plan describes WHAT to create, not HOW to create it.
41
+ The executor is responsible for executing this plan.
42
+
43
+ Attributes:
44
+ inheritance_chain: List of model classes from root to child
45
+ parent_levels: List of ParentLevel objects, one per parent model
46
+ child_objects: List of child instances to create (not yet with parent links)
47
+ child_model: The child model class
48
+ original_objects: Original objects provided by user
49
+ batch_size: Batch size for operations
50
+ existing_record_ids: Set of id() of original objects that represent existing DB records
51
+ update_conflicts: Whether this is an upsert operation
52
+ unique_fields: Fields used for conflict detection (original, unfiltered)
53
+ update_fields: Fields to update on conflict (original, unfiltered)
54
+ child_unique_fields: Pre-filtered field objects for child table conflict detection
55
+ child_update_fields: Pre-filtered field objects for child table updates
56
+ """
57
+
58
+ inheritance_chain: list[Any]
59
+ parent_levels: list[ParentLevel]
60
+ child_objects: list[Any]
61
+ child_model: Any
62
+ original_objects: list[Any]
63
+ batch_size: int = None
64
+ existing_record_ids: set = field(default_factory=set)
65
+ update_conflicts: bool = False
66
+ unique_fields: list[str] = field(default_factory=list)
67
+ update_fields: list[str] = field(default_factory=list)
68
+ child_unique_fields: list = field(default_factory=list) # Field objects for child table
69
+ child_update_fields: list = field(default_factory=list) # Field objects for child table
70
+
71
+
72
+ @dataclass
73
+ class ModelFieldGroup:
74
+ """
75
+ Represents fields to update for one model in the inheritance chain.
76
+
77
+ Attributes:
78
+ model_class: The model class
79
+ fields: List of field names to update on this model
80
+ filter_field: Field to use for filtering (e.g., 'pk' or parent link attname)
81
+ """
82
+
83
+ model_class: Any
84
+ fields: list[str]
85
+ filter_field: str = "pk"
86
+
87
+
88
+ @dataclass
89
+ class MTIUpdatePlan:
90
+ """
91
+ Plan for executing bulk_update on an MTI model.
92
+
93
+ Attributes:
94
+ inheritance_chain: List of model classes from root to child
95
+ field_groups: List of ModelFieldGroup objects
96
+ objects: Objects to update
97
+ batch_size: Batch size for operations
98
+ """
99
+
100
+ inheritance_chain: list[Any]
101
+ field_groups: list[ModelFieldGroup]
102
+ objects: list[Any]
103
+ batch_size: int = None
@@ -64,7 +64,7 @@ class RecordClassifier:
64
64
  # Build lookup dict for this object's unique fields
65
65
  lookup = {}
66
66
  normalized_values = []
67
-
67
+
68
68
  for field_name in unique_fields:
69
69
  # Use centralized field value extraction for consistent FK handling
70
70
  value = get_field_value_for_db(obj, field_name, query_model)
@@ -11,6 +11,8 @@ import logging
11
11
  from django.db import models
12
12
  from django.db import transaction
13
13
 
14
+ from django_bulk_hooks.helpers import extract_pks
15
+
14
16
  logger = logging.getLogger(__name__)
15
17
 
16
18
 
@@ -132,7 +134,11 @@ class HookQuerySet(models.QuerySet):
132
134
 
133
135
  @transaction.atomic
134
136
  def bulk_delete(
135
- self, objs, bypass_hooks=False, bypass_validation=False, **kwargs,
137
+ self,
138
+ objs,
139
+ bypass_hooks=False,
140
+ bypass_validation=False,
141
+ **kwargs,
136
142
  ):
137
143
  """
138
144
  Delete multiple objects with hook support.
@@ -148,7 +154,7 @@ class HookQuerySet(models.QuerySet):
148
154
  Tuple of (count, details dict)
149
155
  """
150
156
  # Filter queryset to only these objects
151
- pks = [obj.pk for obj in objs if obj.pk is not None]
157
+ pks = extract_pks(objs)
152
158
  if not pks:
153
159
  return 0
154
160
 
@@ -116,7 +116,6 @@ class HookRegistry:
116
116
  if not self._hooks[key]:
117
117
  del self._hooks[key]
118
118
 
119
-
120
119
  def clear(self) -> None:
121
120
  """
122
121
  Clear all registered hooks.
@@ -132,7 +131,6 @@ class HookRegistry:
132
131
  HookMeta._registered.clear()
133
132
  HookMeta._class_hook_map.clear()
134
133
 
135
-
136
134
  def list_all(self) -> dict[tuple[type, str], list[HookInfo]]:
137
135
  """
138
136
  Get all registered hooks for debugging.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: django-bulk-hooks
3
- Version: 0.2.60
3
+ Version: 0.2.62
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
@@ -0,0 +1,27 @@
1
+ django_bulk_hooks/__init__.py,sha256=ujBvX-GY4Pg4ACBh7RXm_MOmi2eAowf5s7pG2SXWdpo,2276
2
+ django_bulk_hooks/changeset.py,sha256=qnMD3bR2cNh8ZM8J6ASR5ly5Rjx-tPzXBYkqIjKGW98,6568
3
+ django_bulk_hooks/conditions.py,sha256=ar4pGjtxLKmgSIlO4S6aZFKmaBNchLtxMmWpkn4g9RU,8114
4
+ django_bulk_hooks/constants.py,sha256=PxpEETaO6gdENcTPoXS586lerGKVP3nmjpDvOkmhYxI,509
5
+ django_bulk_hooks/context.py,sha256=mqaC5-yESDTA5ruI7fuXlt8qSgKuOFp0mjq7h1-4HdQ,1926
6
+ django_bulk_hooks/decorators.py,sha256=TdkO4FJyFrVU2zqK6Y_6JjEJ4v3nbKkk7aa22jN10sk,11994
7
+ django_bulk_hooks/dispatcher.py,sha256=yHfmAWChj9rsZwO4jhYDVtJde_Z8bPe9WHRjkYBMfEo,8151
8
+ django_bulk_hooks/enums.py,sha256=Zo8_tJzuzZ2IKfVc7gZ-0tWPT8q1QhqZbAyoh9ZVJbs,381
9
+ django_bulk_hooks/factory.py,sha256=ezrVM5U023KZqOBbJXb6lYUP-pE7WJmi8Olh2Ew-7RA,18085
10
+ django_bulk_hooks/handler.py,sha256=SRCrMzgolrruTkvMnYBFmXLR-ABiw0JiH3605PEdCZM,4207
11
+ django_bulk_hooks/helpers.py,sha256=tMxUI5oWhbtWByzCCR0Qcj1CgZ6iP5Jfx03EqVmEhxU,7597
12
+ django_bulk_hooks/manager.py,sha256=aDuP87DZLWWbDK2qeA7usl3pxoIjHFIWnQNi_jEq6z0,4446
13
+ django_bulk_hooks/models.py,sha256=TWN_F-SsLGPx9jrkNT9pmJFR5VsZ0Z_QaVOZOmt7bpw,2434
14
+ django_bulk_hooks/operations/__init__.py,sha256=BtJYjmRhe_sScivLsniDaZmBkm0ZLvcmzXFKL7QY2Xg,550
15
+ django_bulk_hooks/operations/analyzer.py,sha256=Pz8mc-EL8KDOfLQFYiRuN-r0OmINW3nIBhRJJCma-yo,10360
16
+ django_bulk_hooks/operations/bulk_executor.py,sha256=po8V_2H3ULiE0RYJ-wbaRIz52SKhss81UHwuQjlz3H8,26214
17
+ django_bulk_hooks/operations/coordinator.py,sha256=NPPkiEIMgbJXEIOtBqvy3OH4l0pOK_NL5jwT7Og9I4o,33765
18
+ django_bulk_hooks/operations/field_utils.py,sha256=cQ9w4xdk-z3PrMLFvRzVV07Wc0D2qbpSepwoupqwQH8,7888
19
+ django_bulk_hooks/operations/mti_handler.py,sha256=Vmz0C0gtYDvbybmb4cDzIaGglSaQK4DQVkaBK-WuQeE,25855
20
+ django_bulk_hooks/operations/mti_plans.py,sha256=HIRJgogHPpm6MV7nZZ-sZhMLUnozpZPV2SzwQHLRzYc,3667
21
+ django_bulk_hooks/operations/record_classifier.py,sha256=It85hJC2K-UsEOLbTR-QBdY5UPV-acQIJ91TSGa7pYo,7053
22
+ django_bulk_hooks/queryset.py,sha256=g_9OtOTC8FXY0hBwYr2FCqQ3mYXbfJTFPLlFV3SHmWQ,5600
23
+ django_bulk_hooks/registry.py,sha256=4HxP1mVK2z4VzvlohbEw2359wM21UJZJYagJJ1komM0,7947
24
+ django_bulk_hooks-0.2.62.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
25
+ django_bulk_hooks-0.2.62.dist-info/METADATA,sha256=Ib--glZc6N4AtvIcIGqMAQUTdAk0AeCmrV2wv6u8iWQ,9265
26
+ django_bulk_hooks-0.2.62.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
27
+ django_bulk_hooks-0.2.62.dist-info/RECORD,,
@@ -1,27 +0,0 @@
1
- django_bulk_hooks/__init__.py,sha256=ujBvX-GY4Pg4ACBh7RXm_MOmi2eAowf5s7pG2SXWdpo,2276
2
- django_bulk_hooks/changeset.py,sha256=wU6wckJEQ_hG5UZq_9g_kWODoKwEj99JrtacVUQ9BxA,7445
3
- django_bulk_hooks/conditions.py,sha256=v2DMFmWI7bppBQw5qdbO5CmQRN_QtUwnBjcyKBJLLbw,8030
4
- django_bulk_hooks/constants.py,sha256=PxpEETaO6gdENcTPoXS586lerGKVP3nmjpDvOkmhYxI,509
5
- django_bulk_hooks/context.py,sha256=mqaC5-yESDTA5ruI7fuXlt8qSgKuOFp0mjq7h1-4HdQ,1926
6
- django_bulk_hooks/decorators.py,sha256=P7cvzFgORJRW-YQHNAxNXqQOP9OywBmA7Rz9kiJoxUk,12237
7
- django_bulk_hooks/dispatcher.py,sha256=CiKYe5ecUPu5TYUZq8ToaRT40TkLc5l5mczgf5XDzGA,8217
8
- django_bulk_hooks/enums.py,sha256=Zo8_tJzuzZ2IKfVc7gZ-0tWPT8q1QhqZbAyoh9ZVJbs,381
9
- django_bulk_hooks/factory.py,sha256=ezrVM5U023KZqOBbJXb6lYUP-pE7WJmi8Olh2Ew-7RA,18085
10
- django_bulk_hooks/handler.py,sha256=38ejMdQ9reYA07_XQ9tC8xv0lW3amO-m8gPzuRNOyj0,4200
11
- django_bulk_hooks/helpers.py,sha256=Nw8eXryLUUquW7AgiuKp0PQT3Pq6HAHsdP-xAtqhmjA,3216
12
- django_bulk_hooks/manager.py,sha256=3mFzB0ZzHHeXWdKGObZD_H0NlskHJc8uYBF69KKdAXU,4068
13
- django_bulk_hooks/models.py,sha256=4Vvi2LiGP0g4j08a5liqBROfsO8Wd_ermBoyjKwfrPU,2512
14
- django_bulk_hooks/operations/__init__.py,sha256=BtJYjmRhe_sScivLsniDaZmBkm0ZLvcmzXFKL7QY2Xg,550
15
- django_bulk_hooks/operations/analyzer.py,sha256=wAG8sAG9NwfwNqG9z81VfGR7AANDzRmMGE_o82MWji4,10689
16
- django_bulk_hooks/operations/bulk_executor.py,sha256=0_r9qaOMl9RJpi9eE3GrdUAlXA6ZU016nHYeIZ-yiPE,28279
17
- django_bulk_hooks/operations/coordinator.py,sha256=1Ka5eZJXTFjx3tr-BD6Tr350Y2T57SUOX3vjagBYBvM,32193
18
- django_bulk_hooks/operations/field_utils.py,sha256=Tvr5bcZLG8imH-r2S85oui1Cbw6hGv3VtuIMn4OvsU4,2895
19
- django_bulk_hooks/operations/mti_handler.py,sha256=pguym-6vqaLxu-lY7gnb5laKT9RJQlUciNw1SflZ1Zs,25574
20
- django_bulk_hooks/operations/mti_plans.py,sha256=7STQ2oA2ZT8cEG3-t-6xciRAdf7OeSf0gRLXR_BRG-Q,3363
21
- django_bulk_hooks/operations/record_classifier.py,sha256=kqML4aO11X9K3SSJ5DUlUukwI172j_Tk12Kr77ee8q8,7065
22
- django_bulk_hooks/queryset.py,sha256=aQitlbexcVnmeAdc0jtO3hci39p4QEu4srQPEzozy5s,5546
23
- django_bulk_hooks/registry.py,sha256=uum5jhGI3TPaoiXuA1MdBdu4gbE3rQGGwQ5YDjiMcjk,7949
24
- django_bulk_hooks-0.2.60.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
25
- django_bulk_hooks-0.2.60.dist-info/METADATA,sha256=tYgGJtWSG7Zx360peLawbsJAiIkT-BwF7WuJg4JfkJM,9265
26
- django_bulk_hooks-0.2.60.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
27
- django_bulk_hooks-0.2.60.dist-info/RECORD,,