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

@@ -8,18 +8,18 @@ class BulkHookManager(models.Manager):
8
8
  # Use super().get_queryset() to let Django and MRO build the queryset
9
9
  # This ensures cooperation with other managers
10
10
  base_queryset = super().get_queryset()
11
-
11
+
12
12
  # If the base queryset already has hook functionality, return it as-is
13
13
  if isinstance(base_queryset, HookQuerySetMixin):
14
14
  return base_queryset
15
-
15
+
16
16
  # Otherwise, create a new HookQuerySet with the same parameters
17
17
  # This is much simpler and avoids dynamic class creation issues
18
18
  return HookQuerySet(
19
19
  model=base_queryset.model,
20
20
  query=base_queryset.query,
21
21
  using=base_queryset._db,
22
- hints=base_queryset._hints
22
+ hints=base_queryset._hints,
23
23
  )
24
24
 
25
25
  def bulk_create(
@@ -50,9 +50,7 @@ class BulkHookManager(models.Manager):
50
50
  **kwargs,
51
51
  )
52
52
 
53
- def bulk_update(
54
- self, objs, bypass_hooks=False, bypass_validation=False, **kwargs
55
- ):
53
+ def bulk_update(self, objs, bypass_hooks=False, bypass_validation=False, **kwargs):
56
54
  """
57
55
  Delegate to QuerySet's bulk_update implementation.
58
56
  This follows Django's pattern where Manager methods call QuerySet methods.
@@ -975,216 +975,308 @@ class HookQuerySetMixin:
975
975
 
976
976
  @transaction.atomic
977
977
  def bulk_update(self, objs, bypass_hooks=False, bypass_validation=False, **kwargs):
978
+ if not objs:
979
+ return []
980
+
981
+ self._validate_objects(objs)
982
+
983
+ changed_fields = self._detect_changed_fields(objs)
984
+ is_mti = self._is_multi_table_inheritance()
985
+ hook_context, originals = self._init_hook_context(bypass_hooks, objs)
986
+
987
+ fields_set, auto_now_fields, custom_update_fields = self._prepare_update_fields(
988
+ changed_fields
989
+ )
990
+
991
+ self._apply_auto_now_fields(objs, auto_now_fields)
992
+ self._apply_custom_update_fields(objs, custom_update_fields, fields_set)
993
+
994
+ if is_mti:
995
+ return self._mti_bulk_update(objs, list(fields_set), **kwargs)
996
+ else:
997
+ return self._single_table_bulk_update(
998
+ objs, fields_set, auto_now_fields, **kwargs
999
+ )
1000
+
1001
+ def _apply_custom_update_fields(self, objs, custom_update_fields, fields_set):
978
1002
  """
979
- Bulk update objects in the database with MTI support.
980
- Automatically detects which fields have changed by comparing with database values.
1003
+ Call pre_save() for custom fields that require update handling
1004
+ (e.g., CurrentUserField) and update both the objects and the field set.
1005
+
1006
+ Args:
1007
+ objs (list[Model]): The model instances being updated.
1008
+ custom_update_fields (list[Field]): Fields that define a pre_save() hook.
1009
+ fields_set (set[str]): The overall set of fields to update, mutated in place.
981
1010
  """
1011
+ if not custom_update_fields:
1012
+ return
1013
+
982
1014
  model_cls = self.model
1015
+ pk_field_names = [f.name for f in model_cls._meta.pk_fields]
983
1016
 
984
- if not objs:
985
- return []
1017
+ logger.debug(
1018
+ "Applying pre_save() on custom update fields: %s",
1019
+ [f.name for f in custom_update_fields],
1020
+ )
986
1021
 
987
- if any(not isinstance(obj, model_cls) for obj in objs):
1022
+ for obj in objs:
1023
+ for field in custom_update_fields:
1024
+ try:
1025
+ # Call pre_save with add=False (since this is an update)
1026
+ new_value = field.pre_save(obj, add=False)
1027
+
1028
+ # Only assign if pre_save returned something
1029
+ if new_value is not None:
1030
+ setattr(obj, field.name, new_value)
1031
+
1032
+ # Ensure this field is included in the update set
1033
+ if (
1034
+ field.name not in fields_set
1035
+ and field.name not in pk_field_names
1036
+ ):
1037
+ fields_set.add(field.name)
1038
+
1039
+ logger.debug(
1040
+ "Custom field %s updated via pre_save() for object %s",
1041
+ field.name,
1042
+ obj.pk,
1043
+ )
1044
+
1045
+ except Exception as e:
1046
+ logger.warning(
1047
+ "Failed to call pre_save() on custom field %s for object %s: %s",
1048
+ field.name,
1049
+ getattr(obj, "pk", None),
1050
+ e,
1051
+ )
1052
+
1053
+ def _single_table_bulk_update(self, objs, fields_set, auto_now_fields, **kwargs):
1054
+ """
1055
+ Perform bulk_update for single-table models, handling Django semantics
1056
+ for kwargs and setting a value map for hook execution.
1057
+
1058
+ Args:
1059
+ objs (list[Model]): The model instances being updated.
1060
+ fields_set (set[str]): The names of fields to update.
1061
+ auto_now_fields (list[str]): Names of auto_now fields included in update.
1062
+ **kwargs: Extra arguments (only Django-supported ones are passed through).
1063
+
1064
+ Returns:
1065
+ list[Model]: The updated model instances.
1066
+ """
1067
+ # Strip out unsupported bulk_update kwargs
1068
+ django_kwargs = self._filter_django_kwargs(kwargs)
1069
+
1070
+ # Build a value map: {pk -> {field: raw_value}} for later hook use
1071
+ value_map = self._build_value_map(objs, fields_set, auto_now_fields)
1072
+
1073
+ if value_map:
1074
+ set_bulk_update_value_map(value_map)
1075
+
1076
+ try:
1077
+ logger.debug(
1078
+ "Calling Django bulk_update for %d objects on fields %s",
1079
+ len(objs),
1080
+ list(fields_set),
1081
+ )
1082
+ return super().bulk_update(objs, list(fields_set), **django_kwargs)
1083
+ finally:
1084
+ # Always clear thread-local state
1085
+ set_bulk_update_value_map(None)
1086
+
1087
+ def _filter_django_kwargs(self, kwargs):
1088
+ """
1089
+ Remove unsupported arguments before passing to Django's bulk_update.
1090
+ """
1091
+ unsupported = {
1092
+ "unique_fields",
1093
+ "update_conflicts",
1094
+ "update_fields",
1095
+ "ignore_conflicts",
1096
+ }
1097
+ passthrough = {}
1098
+ for k, v in kwargs.items():
1099
+ if k in unsupported:
1100
+ logger.warning(
1101
+ "Parameter '%s' is not supported by bulk_update. "
1102
+ "It is only available for bulk_create UPSERT operations.",
1103
+ k,
1104
+ )
1105
+ elif k not in {"bypass_hooks", "bypass_validation"}:
1106
+ passthrough[k] = v
1107
+ return passthrough
1108
+
1109
+ def _build_value_map(self, objs, fields_set, auto_now_fields):
1110
+ """
1111
+ Build a mapping of {pk -> {field_name: raw_value}} for hook processing.
1112
+
1113
+ Expressions are not included; only concrete values assigned on the object.
1114
+ """
1115
+ value_map = {}
1116
+ for obj in objs:
1117
+ if obj.pk is None:
1118
+ continue # skip unsaved objects
1119
+ field_values = {}
1120
+ for field_name in fields_set:
1121
+ value = getattr(obj, field_name)
1122
+ field_values[field_name] = value
1123
+ if field_name in auto_now_fields:
1124
+ logger.debug("Object %s %s=%s", obj.pk, field_name, value)
1125
+ if field_values:
1126
+ value_map[obj.pk] = field_values
1127
+
1128
+ logger.debug("Built value_map for %d objects", len(value_map))
1129
+ return value_map
1130
+
1131
+ def _validate_objects(self, objs):
1132
+ """
1133
+ Validate that all objects are instances of this queryset's model
1134
+ and that they have primary keys (cannot bulk update unsaved objects).
1135
+ """
1136
+ model_cls = self.model
1137
+
1138
+ # Type check
1139
+ invalid_types = {
1140
+ type(obj).__name__ for obj in objs if not isinstance(obj, model_cls)
1141
+ }
1142
+ if invalid_types:
988
1143
  raise TypeError(
989
- f"bulk_update expected instances of {model_cls.__name__}, but got {set(type(obj).__name__ for obj in objs)}"
1144
+ f"bulk_update expected instances of {model_cls.__name__}, "
1145
+ f"but got {invalid_types}"
990
1146
  )
991
1147
 
992
- # Auto-detect changed fields by comparing with database values
993
- changed_fields = self._detect_changed_fields(objs)
994
- logger.debug(f"Auto-detected changed fields: {changed_fields}")
1148
+ # Primary key check
1149
+ missing_pks = [obj for obj in objs if obj.pk is None]
1150
+ if missing_pks:
1151
+ raise ValueError(
1152
+ f"bulk_update cannot operate on unsaved {model_cls.__name__} instances. "
1153
+ f"{len(missing_pks)} object(s) have no primary key."
1154
+ )
995
1155
 
996
1156
  logger.debug(
997
- f"bulk_update {model_cls.__name__} bypass_hooks={bypass_hooks} objs={len(objs)} changed_fields={changed_fields}"
998
- )
999
- print(
1000
- f"DEBUG: bulk_update {model_cls.__name__} bypass_hooks={bypass_hooks} objs={len(objs)} changed_fields={changed_fields}"
1157
+ "Validated %d %s objects for bulk_update",
1158
+ len(objs),
1159
+ model_cls.__name__,
1001
1160
  )
1002
1161
 
1003
- # Check for MTI
1004
- is_mti = False
1005
- for parent in model_cls._meta.all_parents:
1006
- if parent._meta.concrete_model is not model_cls._meta.concrete_model:
1007
- is_mti = True
1008
- break
1162
+ def _init_hook_context(self, bypass_hooks: bool, objs):
1163
+ """
1164
+ Initialize the hook context for bulk_update.
1009
1165
 
1010
- if not bypass_hooks:
1011
- logger.debug("bulk_update: hooks will run in update()")
1012
- ctx = HookContext(model_cls, bypass_hooks=False)
1013
- originals = [None] * len(objs) # Placeholder for after_update call
1014
- else:
1015
- logger.debug("bulk_update: hooks bypassed")
1166
+ Returns:
1167
+ (HookContext, list): The hook context and a placeholder list
1168
+ for 'originals', which can be populated later if needed for
1169
+ after_update hooks.
1170
+ """
1171
+ model_cls = self.model
1172
+
1173
+ if bypass_hooks:
1174
+ logger.debug("bulk_update: hooks bypassed for %s", model_cls.__name__)
1016
1175
  ctx = HookContext(model_cls, bypass_hooks=True)
1017
- originals = [None] * len(
1018
- objs
1019
- ) # Ensure originals is defined for after_update call
1176
+ else:
1177
+ logger.debug("bulk_update: hooks enabled for %s", model_cls.__name__)
1178
+ ctx = HookContext(model_cls, bypass_hooks=False)
1179
+
1180
+ # Keep `originals` aligned with objs to support later hook execution.
1181
+ originals = [None] * len(objs)
1182
+
1183
+ return ctx, originals
1184
+
1185
+ def _prepare_update_fields(self, changed_fields):
1186
+ """
1187
+ Determine the final set of fields to update, including auto_now
1188
+ fields and custom fields that require pre_save() on updates.
1189
+
1190
+ Args:
1191
+ changed_fields (Iterable[str]): Fields detected as changed.
1020
1192
 
1021
- # Handle auto_now fields like Django's update_or_create does
1193
+ Returns:
1194
+ tuple:
1195
+ fields_set (set): All fields that should be updated.
1196
+ auto_now_fields (list[str]): Fields that require auto_now behavior.
1197
+ custom_update_fields (list[Field]): Fields with pre_save hooks to call.
1198
+ """
1199
+ model_cls = self.model
1022
1200
  fields_set = set(changed_fields)
1023
- pk_fields = model_cls._meta.pk_fields
1024
- pk_field_names = [f.name for f in pk_fields]
1201
+ pk_field_names = [f.name for f in model_cls._meta.pk_fields]
1202
+
1025
1203
  auto_now_fields = []
1026
- custom_update_fields = [] # Fields that need pre_save() called on update
1027
- logger.debug(
1028
- f"Checking for auto_now and custom update fields in {model_cls.__name__}"
1029
- )
1204
+ custom_update_fields = []
1205
+
1030
1206
  for field in model_cls._meta.local_concrete_fields:
1031
- # Only add auto_now fields (like updated_at) that aren't already in the fields list
1032
- # Don't include auto_now_add fields (like created_at) as they should only be set on creation
1033
- if hasattr(field, "auto_now") and field.auto_now:
1034
- logger.debug(f"Found auto_now field: {field.name}")
1035
- print(f"DEBUG: Found auto_now field: {field.name}")
1207
+ # Handle auto_now fields
1208
+ if getattr(field, "auto_now", False):
1036
1209
  if field.name not in fields_set and field.name not in pk_field_names:
1037
1210
  fields_set.add(field.name)
1038
- if field.name != field.attname:
1211
+ if field.name != field.attname: # handle attname vs name
1039
1212
  fields_set.add(field.attname)
1040
1213
  auto_now_fields.append(field.name)
1041
- logger.debug(f"Added auto_now field {field.name} to fields list")
1042
- print(f"DEBUG: Added auto_now field {field.name} to fields list")
1043
- else:
1044
- logger.debug(
1045
- f"Auto_now field {field.name} already in fields list or is PK"
1046
- )
1047
- print(
1048
- f"DEBUG: Auto_now field {field.name} already in fields list or is PK"
1049
- )
1050
- elif hasattr(field, "auto_now_add") and field.auto_now_add:
1051
- logger.debug(f"Found auto_now_add field: {field.name} (skipping)")
1052
- # Check for custom fields that might need pre_save() on update (like CurrentUserField)
1214
+ logger.debug("Added auto_now field %s to update set", field.name)
1215
+
1216
+ # Skip auto_now_add (only applies at creation time)
1217
+ elif getattr(field, "auto_now_add", False):
1218
+ continue
1219
+
1220
+ # Handle custom pre_save fields
1053
1221
  elif hasattr(field, "pre_save"):
1054
- # Only call pre_save on fields that aren't already being updated
1055
1222
  if field.name not in fields_set and field.name not in pk_field_names:
1056
1223
  custom_update_fields.append(field)
1057
- logger.debug(f"Found custom field with pre_save: {field.name}")
1058
- print(f"DEBUG: Found custom field with pre_save: {field.name}")
1224
+ logger.debug(
1225
+ "Marked custom field %s for pre_save update", field.name
1226
+ )
1059
1227
 
1060
- logger.debug(f"Auto_now fields detected: {auto_now_fields}")
1061
- print(f"DEBUG: Auto_now fields detected: {auto_now_fields}")
1228
+ logger.debug(
1229
+ "Prepared update fields: fields_set=%s, auto_now_fields=%s, custom_update_fields=%s",
1230
+ fields_set,
1231
+ auto_now_fields,
1232
+ [f.name for f in custom_update_fields],
1233
+ )
1062
1234
 
1063
- # Set auto_now field values to current timestamp
1064
- if auto_now_fields:
1065
- from django.utils import timezone
1235
+ return fields_set, auto_now_fields, custom_update_fields
1066
1236
 
1067
- current_time = timezone.now()
1068
- print(
1069
- f"DEBUG: Setting auto_now fields {auto_now_fields} to current time: {current_time}"
1070
- )
1071
- logger.debug(
1072
- f"Setting auto_now fields {auto_now_fields} to current time: {current_time}"
1073
- )
1074
- for obj in objs:
1075
- for field_name in auto_now_fields:
1076
- setattr(obj, field_name, current_time)
1077
- print(
1078
- f"DEBUG: Set {field_name} to {current_time} for object {obj.pk}"
1079
- )
1237
+ def _apply_auto_now_fields(self, objs, auto_now_fields):
1238
+ """
1239
+ Apply the current timestamp to all auto_now fields on each object.
1080
1240
 
1081
- # Call pre_save() on custom fields that need update handling
1082
- if custom_update_fields:
1083
- logger.debug(
1084
- f"Calling pre_save() on custom update fields: {[f.name for f in custom_update_fields]}"
1085
- )
1086
- print(
1087
- f"DEBUG: Calling pre_save() on custom update fields: {[f.name for f in custom_update_fields]}"
1088
- )
1089
- for obj in objs:
1090
- for field in custom_update_fields:
1091
- try:
1092
- # Call pre_save with add=False to indicate this is an update
1093
- new_value = field.pre_save(obj, add=False)
1094
- # Only update the field if pre_save returned a new value
1095
- if new_value is not None:
1096
- setattr(obj, field.name, new_value)
1097
- # Add this field to the update fields if it's not already there and not a primary key
1098
- if (
1099
- field.name not in fields_set
1100
- and field.name not in pk_field_names
1101
- ):
1102
- fields_set.add(field.name)
1103
- logger.debug(
1104
- f"Custom field {field.name} updated via pre_save() for object {obj.pk}"
1105
- )
1106
- print(
1107
- f"DEBUG: Custom field {field.name} updated via pre_save() for object {obj.pk}"
1108
- )
1109
- except Exception as e:
1110
- logger.warning(
1111
- f"Failed to call pre_save() on custom field {field.name}: {e}"
1112
- )
1113
- print(
1114
- f"DEBUG: Failed to call pre_save() on custom field {field.name}: {e}"
1115
- )
1241
+ Args:
1242
+ objs (list[Model]): The model instances being updated.
1243
+ auto_now_fields (list[str]): Field names that require auto_now behavior.
1244
+ """
1245
+ if not auto_now_fields:
1246
+ return
1116
1247
 
1117
- # Handle MTI models differently
1118
- if is_mti:
1119
- result = self._mti_bulk_update(objs, list(fields_set), **kwargs)
1120
- else:
1121
- # For single-table models, use Django's built-in bulk_update
1122
- # Filter out parameters that are not supported by Django's bulk_update
1123
- unsupported_params = ["unique_fields", "update_conflicts", "update_fields", "ignore_conflicts"]
1124
- django_kwargs = {}
1125
-
1126
- # Check if all objects have primary keys set before proceeding
1127
- if not all(obj._is_pk_set() for obj in objs):
1128
- missing_pk_count = sum(1 for obj in objs if not obj._is_pk_set())
1129
- logger.error(
1130
- f"bulk_update failed: {missing_pk_count} out of {len(objs)} objects don't have primary keys set. "
1131
- "All objects must be saved to the database before bulk_update can be used."
1132
- )
1133
- print(f"ERROR: {missing_pk_count} objects don't have primary keys set")
1134
- raise ValueError(
1135
- f"All bulk_update() objects must have a primary key set. "
1136
- f"{missing_pk_count} out of {len(objs)} objects are missing primary keys."
1137
- )
1248
+ from django.utils import timezone
1138
1249
 
1139
- for k, v in kwargs.items():
1140
- if k in unsupported_params:
1141
- logger.warning(
1142
- f"Parameter '{k}' is not supported by bulk_update. "
1143
- f"This parameter is only available in bulk_create for UPSERT operations."
1144
- )
1145
- print(f"WARNING: Parameter '{k}' is not supported by bulk_update")
1146
- elif k not in ["bypass_hooks", "bypass_validation"]:
1147
- django_kwargs[k] = v
1148
- logger.debug("Calling Django bulk_update")
1149
- print("DEBUG: Calling Django bulk_update")
1150
- # Build a per-object concrete value map to avoid leaking expressions into hooks
1151
- value_map = {}
1152
- logger.debug(
1153
- f"Building value map for {len(objs)} objects with fields: {list(fields_set)}"
1154
- )
1155
- for obj in objs:
1156
- if obj.pk is None:
1157
- continue
1158
- field_values = {}
1159
- for field_name in fields_set:
1160
- # Capture raw values assigned on the object (not expressions)
1161
- field_values[field_name] = getattr(obj, field_name)
1162
- if field_name in auto_now_fields:
1163
- logger.debug(
1164
- f"Object {obj.pk} {field_name}: {field_values[field_name]}"
1165
- )
1166
- if field_values:
1167
- value_map[obj.pk] = field_values
1168
-
1169
- # Make the value map available to the subsequent update() call
1170
- if value_map:
1171
- set_bulk_update_value_map(value_map)
1172
-
1173
- try:
1174
- result = super().bulk_update(objs, list(fields_set), **django_kwargs)
1175
- finally:
1176
- # Always clear after the internal update() path finishes
1177
- set_bulk_update_value_map(None)
1178
- logger.debug(f"Django bulk_update done: {result}")
1179
-
1180
- # Note: We don't run AFTER_UPDATE hooks here to prevent double execution
1181
- # The update() method will handle all hook execution based on thread-local state
1182
- if not bypass_hooks:
1183
- logger.debug("bulk_update: skipping AFTER_UPDATE (update() will handle)")
1184
- else:
1185
- logger.debug("bulk_update: hooks bypassed")
1250
+ current_time = timezone.now()
1186
1251
 
1187
- return result
1252
+ logger.debug(
1253
+ "Setting auto_now fields %s to %s for %d objects",
1254
+ auto_now_fields,
1255
+ current_time,
1256
+ len(objs),
1257
+ )
1258
+
1259
+ for obj in objs:
1260
+ for field_name in auto_now_fields:
1261
+ setattr(obj, field_name, current_time)
1262
+
1263
+ def _is_multi_table_inheritance(self) -> bool:
1264
+ """
1265
+ Determine whether this model uses multi-table inheritance (MTI).
1266
+ Returns True if the model has any concrete parent models other than itself.
1267
+ """
1268
+ model_cls = self.model
1269
+ for parent in model_cls._meta.all_parents:
1270
+ if parent._meta.concrete_model is not model_cls._meta.concrete_model:
1271
+ logger.debug(
1272
+ "%s detected as MTI model (parent: %s)",
1273
+ model_cls.__name__,
1274
+ parent.__name__,
1275
+ )
1276
+ return True
1277
+
1278
+ logger.debug("%s is not an MTI model", model_cls.__name__)
1279
+ return False
1188
1280
 
1189
1281
  def _detect_modified_fields(self, new_instances, original_instances):
1190
1282
  """
@@ -1504,21 +1596,13 @@ class HookQuerySetMixin:
1504
1596
  if inheritance_chain is None:
1505
1597
  inheritance_chain = self._get_inheritance_chain()
1506
1598
 
1507
- # Check if all objects have primary keys set before proceeding
1508
- if not all(obj._is_pk_set() for obj in objs):
1509
- missing_pk_count = sum(1 for obj in objs if not obj._is_pk_set())
1510
- logger.error(
1511
- f"MTI bulk_update failed: {missing_pk_count} out of {len(objs)} objects don't have primary keys set. "
1512
- "All objects must be saved to the database before bulk_update can be used."
1513
- )
1514
- print(f"ERROR: {missing_pk_count} objects don't have primary keys set")
1515
- raise ValueError(
1516
- f"All bulk_update() objects must have a primary key set. "
1517
- f"{missing_pk_count} out of {len(objs)} objects are missing primary keys."
1518
- )
1519
-
1520
1599
  # Remove custom hook kwargs and unsupported parameters before passing to Django internals
1521
- unsupported_params = ["unique_fields", "update_conflicts", "update_fields", "ignore_conflicts"]
1600
+ unsupported_params = [
1601
+ "unique_fields",
1602
+ "update_conflicts",
1603
+ "update_fields",
1604
+ "ignore_conflicts",
1605
+ ]
1522
1606
  django_kwargs = {}
1523
1607
  for k, v in kwargs.items():
1524
1608
  if k in unsupported_params:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: django-bulk-hooks
3
- Version: 0.1.266
3
+ Version: 0.1.267
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=k70-BzWwS3wZu_uph5B5qXd6YpwXLQ9hMpOzPUy6i
6
6
  django_bulk_hooks/engine.py,sha256=M3b7Rcb65PYAZTLfWrIRi99BUBPgSLCryL3MSjMVlfQ,2663
7
7
  django_bulk_hooks/enums.py,sha256=Zo8_tJzuzZ2IKfVc7gZ-0tWPT8q1QhqZbAyoh9ZVJbs,381
8
8
  django_bulk_hooks/handler.py,sha256=Bx-W6yyiciKMyy-BRxUt3CmRPCrX9_LhQgU-5LaJTjg,6019
9
- django_bulk_hooks/manager.py,sha256=mk2RYm-iBk7xYTcYfuo7XPHJbPP5TCTns5IxJMwRY2M,3867
9
+ django_bulk_hooks/manager.py,sha256=3jNWL-EkvGScsliNc7mW-ozQCG6HyaEevI1u1BFS4AA,3836
10
10
  django_bulk_hooks/models.py,sha256=WtSfc4GBOG_oOt8n37cVvid0MtFIGze9JYKSixil2y0,4370
11
11
  django_bulk_hooks/priority.py,sha256=HG_2D35nga68lBCZmSXTcplXrjFoRgZFRDOy4ROKonY,376
12
- django_bulk_hooks/queryset.py,sha256=hq2PHSFM3N0GBFXekYT6FGFHHM85uoJWpQVj4vnDG_s,84452
12
+ django_bulk_hooks/queryset.py,sha256=xp8Xa2yxc278A11Voy0sx5eYn6O5p2y1nzuEB57q-Tg,84694
13
13
  django_bulk_hooks/registry.py,sha256=GRUTGVQEO2sdkC9OaZ9Q3U7mM-3Ix83uTyvrlTtpatw,1317
14
- django_bulk_hooks-0.1.266.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
15
- django_bulk_hooks-0.1.266.dist-info/METADATA,sha256=HjwwuWICGq1svF5aeNWtksQLwIkuenJdRC9N2PyT5ds,9115
16
- django_bulk_hooks-0.1.266.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
17
- django_bulk_hooks-0.1.266.dist-info/RECORD,,
14
+ django_bulk_hooks-0.1.267.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
15
+ django_bulk_hooks-0.1.267.dist-info/METADATA,sha256=WqAB7A5yKuD9PKX9bte-a3kk7MkhrUG8AQ_-xqoNJaE,9115
16
+ django_bulk_hooks-0.1.267.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
17
+ django_bulk_hooks-0.1.267.dist-info/RECORD,,