plain.models 0.41.1__py3-none-any.whl → 0.43.0__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.
@@ -152,7 +152,6 @@ class MigrationAutodetector:
152
152
  self.generate_deleted_models()
153
153
  self.generate_created_models()
154
154
  self.generate_altered_options()
155
- self.generate_altered_managers()
156
155
  self.generate_altered_db_table_comment()
157
156
 
158
157
  # Create the renamed fields and store them in self.renamed_fields.
@@ -600,7 +599,6 @@ class MigrationAutodetector:
600
599
  ],
601
600
  options=model_state.options,
602
601
  bases=model_state.bases,
603
- managers=model_state.managers,
604
602
  ),
605
603
  dependencies=dependencies,
606
604
  beginning=True,
@@ -1258,22 +1256,6 @@ class MigrationAutodetector:
1258
1256
  ),
1259
1257
  )
1260
1258
 
1261
- def generate_altered_managers(self):
1262
- for package_label, model_name in sorted(self.kept_model_keys):
1263
- old_model_name = self.renamed_models.get(
1264
- (package_label, model_name), model_name
1265
- )
1266
- old_model_state = self.from_state.models[package_label, old_model_name]
1267
- new_model_state = self.to_state.models[package_label, model_name]
1268
- if old_model_state.managers != new_model_state.managers:
1269
- self.add_operation(
1270
- package_label,
1271
- operations.AlterModelManagers(
1272
- name=model_name,
1273
- managers=new_model_state.managers,
1274
- ),
1275
- )
1276
-
1277
1259
  def arrange_for_graph(self, changes, graph, migration_name=None):
1278
1260
  """
1279
1261
  Take a result from changes() and a MigrationGraph, and fix the names
@@ -2,7 +2,6 @@ from .fields import AddField, AlterField, RemoveField, RenameField
2
2
  from .models import (
3
3
  AddConstraint,
4
4
  AddIndex,
5
- AlterModelManagers,
6
5
  AlterModelOptions,
7
6
  AlterModelTable,
8
7
  AlterModelTableComment,
@@ -34,5 +33,4 @@ __all__ = [
34
33
  "SeparateDatabaseAndState",
35
34
  "RunSQL",
36
35
  "RunPython",
37
- "AlterModelManagers",
38
36
  ]
@@ -41,16 +41,14 @@ class ModelOperation(Operation):
41
41
  class CreateModel(ModelOperation):
42
42
  """Create a model's table."""
43
43
 
44
- serialization_expand_args = ["fields", "options", "managers"]
44
+ serialization_expand_args = ["fields", "options"]
45
45
 
46
- def __init__(self, name, fields, options=None, bases=None, managers=None):
46
+ def __init__(self, name, fields, options=None, bases=None):
47
47
  self.fields = fields
48
48
  self.options = options or {}
49
49
  self.bases = bases or (models.Model,)
50
- self.managers = managers or []
51
50
  super().__init__(name)
52
- # Sanity-check that there are no duplicated field names, bases, or
53
- # manager names
51
+ # Sanity-check that there are no duplicated field names or bases
54
52
  _check_for_duplicates("fields", (name for name, _ in self.fields))
55
53
  _check_for_duplicates(
56
54
  "bases",
@@ -63,7 +61,6 @@ class CreateModel(ModelOperation):
63
61
  for base in self.bases
64
62
  ),
65
63
  )
66
- _check_for_duplicates("managers", (name for name, _ in self.managers))
67
64
 
68
65
  def deconstruct(self):
69
66
  kwargs = {
@@ -74,8 +71,6 @@ class CreateModel(ModelOperation):
74
71
  kwargs["options"] = self.options
75
72
  if self.bases and self.bases != (models.Model,):
76
73
  kwargs["bases"] = self.bases
77
- if self.managers and self.managers != [("objects", models.Manager())]:
78
- kwargs["managers"] = self.managers
79
74
  return (self.__class__.__qualname__, [], kwargs)
80
75
 
81
76
  def state_forwards(self, package_label, state):
@@ -86,7 +81,6 @@ class CreateModel(ModelOperation):
86
81
  list(self.fields),
87
82
  dict(self.options),
88
83
  tuple(self.bases),
89
- list(self.managers),
90
84
  )
91
85
  )
92
86
 
@@ -141,7 +135,6 @@ class CreateModel(ModelOperation):
141
135
  fields=self.fields,
142
136
  options=self.options,
143
137
  bases=self.bases,
144
- managers=self.managers,
145
138
  ),
146
139
  ]
147
140
  elif (
@@ -158,20 +151,6 @@ class CreateModel(ModelOperation):
158
151
  fields=self.fields,
159
152
  options=options,
160
153
  bases=self.bases,
161
- managers=self.managers,
162
- ),
163
- ]
164
- elif (
165
- isinstance(operation, AlterModelManagers)
166
- and self.name_lower == operation.name_lower
167
- ):
168
- return [
169
- CreateModel(
170
- self.name,
171
- fields=self.fields,
172
- options=self.options,
173
- bases=self.bases,
174
- managers=operation.managers,
175
154
  ),
176
155
  ]
177
156
  elif (
@@ -185,7 +164,6 @@ class CreateModel(ModelOperation):
185
164
  fields=self.fields + [(operation.name, operation.field)],
186
165
  options=self.options,
187
166
  bases=self.bases,
188
- managers=self.managers,
189
167
  ),
190
168
  ]
191
169
  elif isinstance(operation, AlterField):
@@ -198,7 +176,6 @@ class CreateModel(ModelOperation):
198
176
  ],
199
177
  options=self.options,
200
178
  bases=self.bases,
201
- managers=self.managers,
202
179
  ),
203
180
  ]
204
181
  elif isinstance(operation, RemoveField):
@@ -214,7 +191,6 @@ class CreateModel(ModelOperation):
214
191
  ],
215
192
  options=options,
216
193
  bases=self.bases,
217
- managers=self.managers,
218
194
  ),
219
195
  ]
220
196
  elif isinstance(operation, RenameField):
@@ -229,7 +205,6 @@ class CreateModel(ModelOperation):
229
205
  ],
230
206
  options=options,
231
207
  bases=self.bases,
232
- managers=self.managers,
233
208
  ),
234
209
  ]
235
210
  return super().reduce(operation, package_label)
@@ -447,9 +422,6 @@ class AlterModelOptions(ModelOptionOperation):
447
422
 
448
423
  # Model options we want to compare and preserve in an AlterModelOptions op
449
424
  ALTER_OPTION_KEYS = [
450
- "base_manager_name",
451
- "default_manager_name",
452
- "default_related_name",
453
425
  "ordering",
454
426
  ]
455
427
 
@@ -483,32 +455,6 @@ class AlterModelOptions(ModelOptionOperation):
483
455
  return f"alter_{self.name_lower}_options"
484
456
 
485
457
 
486
- class AlterModelManagers(ModelOptionOperation):
487
- """Alter the model's managers."""
488
-
489
- serialization_expand_args = ["managers"]
490
-
491
- def __init__(self, name, managers):
492
- self.managers = managers
493
- super().__init__(name)
494
-
495
- def deconstruct(self):
496
- return (self.__class__.__qualname__, [self.name, self.managers], {})
497
-
498
- def state_forwards(self, package_label, state):
499
- state.alter_model_managers(package_label, self.name_lower, self.managers)
500
-
501
- def database_forwards(self, package_label, schema_editor, from_state, to_state):
502
- pass
503
-
504
- def describe(self):
505
- return f"Change managers on {self.name}"
506
-
507
- @property
508
- def migration_name_fragment(self):
509
- return f"alter_{self.name_lower}_managers"
510
-
511
-
512
458
  class IndexOperation(Operation):
513
459
  option_name = "indexes"
514
460
 
@@ -49,10 +49,9 @@ class RunSQL(Operation):
49
49
  by this SQL change, in case it's custom column/table creation/deletion.
50
50
  """
51
51
 
52
- def __init__(self, sql, *, state_operations=None, hints=None, elidable=False):
52
+ def __init__(self, sql, *, state_operations=None, elidable=False):
53
53
  self.sql = sql
54
54
  self.state_operations = state_operations or []
55
- self.hints = hints or {}
56
55
  self.elidable = elidable
57
56
 
58
57
  def deconstruct(self):
@@ -61,8 +60,6 @@ class RunSQL(Operation):
61
60
  }
62
61
  if self.state_operations:
63
62
  kwargs["state_operations"] = self.state_operations
64
- if self.hints:
65
- kwargs["hints"] = self.hints
66
63
  return (self.__class__.__qualname__, [], kwargs)
67
64
 
68
65
  def state_forwards(self, package_label, state):
@@ -99,13 +96,12 @@ class RunPython(Operation):
99
96
 
100
97
  reduces_to_sql = False
101
98
 
102
- def __init__(self, code, *, atomic=None, hints=None, elidable=False):
99
+ def __init__(self, code, *, atomic=None, elidable=False):
103
100
  self.atomic = atomic
104
101
  # Forwards code
105
102
  if not callable(code):
106
103
  raise ValueError("RunPython must be supplied with a callable")
107
104
  self.code = code
108
- self.hints = hints or {}
109
105
  self.elidable = elidable
110
106
 
111
107
  def deconstruct(self):
@@ -114,8 +110,6 @@ class RunPython(Operation):
114
110
  }
115
111
  if self.atomic is not None:
116
112
  kwargs["atomic"] = self.atomic
117
- if self.hints:
118
- kwargs["hints"] = self.hints
119
113
  return (self.__class__.__qualname__, [], kwargs)
120
114
 
121
115
  def state_forwards(self, package_label, state):
@@ -53,7 +53,7 @@ class MigrationRecorder:
53
53
 
54
54
  @property
55
55
  def migration_qs(self):
56
- return self.Migration.objects.all()
56
+ return self.Migration.query.all()
57
57
 
58
58
  def has_table(self):
59
59
  """Return True if the plainmigrations table exists."""
@@ -215,16 +215,6 @@ class ModelFieldSerializer(DeconstructableSerializer):
215
215
  return self.serialize_deconstructed(path, args, kwargs)
216
216
 
217
217
 
218
- class ModelManagerSerializer(DeconstructableSerializer):
219
- def serialize(self):
220
- as_manager, manager_path, qs_path, args, kwargs = self.value.deconstruct()
221
- if as_manager:
222
- name, imports = self._serialize_path(qs_path)
223
- return f"{name}.as_manager()", imports
224
- else:
225
- return self.serialize_deconstructed(manager_path, args, kwargs)
226
-
227
-
228
218
  class OperationSerializer(BaseSerializer):
229
219
  def serialize(self):
230
220
  from plain.models.migrations.writer import OperationWriter
@@ -359,8 +349,6 @@ def serializer_factory(value):
359
349
 
360
350
  if isinstance(value, models.Field):
361
351
  return ModelFieldSerializer(value)
362
- if isinstance(value, models.manager.BaseManager):
363
- return ModelManagerSerializer(value)
364
352
  if isinstance(value, Operation):
365
353
  return OperationSerializer(value)
366
354
  if isinstance(value, type):
@@ -12,7 +12,6 @@ from plain.models.options import DEFAULT_NAMES
12
12
  from plain.models.registry import ModelsRegistry
13
13
  from plain.models.registry import models_registry as global_models
14
14
  from plain.packages import packages_registry
15
- from plain.utils.module_loading import import_string
16
15
 
17
16
  from .exceptions import InvalidBasesError
18
17
  from .utils import resolve_relation
@@ -176,11 +175,6 @@ class ProjectState:
176
175
  model_state.options.pop(key, False)
177
176
  self.reload_model(package_label, model_name, delay=True)
178
177
 
179
- def alter_model_managers(self, package_label, model_name, managers):
180
- model_state = self.models[package_label, model_name]
181
- model_state.managers = list(managers)
182
- self.reload_model(package_label, model_name, delay=True)
183
-
184
178
  def _append_option(self, package_label, model_name, option_name, obj):
185
179
  model_state = self.models[package_label, model_name]
186
180
  model_state.options[option_name] = [*model_state.options[option_name], obj]
@@ -598,9 +592,7 @@ class ModelState:
598
592
  assign new ones, as these are not detached during a clone.
599
593
  """
600
594
 
601
- def __init__(
602
- self, package_label, name, fields, options=None, bases=None, managers=None
603
- ):
595
+ def __init__(self, package_label, name, fields, options=None, bases=None):
604
596
  self.package_label = package_label
605
597
  self.name = name
606
598
  self.fields = dict(fields)
@@ -608,7 +600,6 @@ class ModelState:
608
600
  self.options.setdefault("indexes", [])
609
601
  self.options.setdefault("constraints", [])
610
602
  self.bases = bases or (models.Model,)
611
- self.managers = managers or []
612
603
  for name, field in self.fields.items():
613
604
  # Sanity-check that fields are NOT already bound to a model.
614
605
  if hasattr(field, "model"):
@@ -711,33 +702,6 @@ class ModelState:
711
702
  ):
712
703
  bases = (models.Model,)
713
704
 
714
- managers = []
715
- manager_names = set()
716
- default_manager_shim = None
717
- for manager in model._meta.managers:
718
- if manager.name in manager_names:
719
- # Skip overridden managers.
720
- continue
721
- elif manager.use_in_migrations:
722
- # Copy managers usable in migrations.
723
- new_manager = copy.copy(manager)
724
- new_manager._set_creation_counter()
725
- elif manager is model._base_manager or manager is model._default_manager:
726
- # Shim custom managers used as default and base managers.
727
- new_manager = models.Manager()
728
- new_manager.model = manager.model
729
- new_manager.name = manager.name
730
- if manager is model._default_manager:
731
- default_manager_shim = new_manager
732
- else:
733
- continue
734
- manager_names.add(manager.name)
735
- managers.append((manager.name, new_manager))
736
-
737
- # Ignore a shimmed default manager called objects if it's the only one.
738
- if managers == [("objects", default_manager_shim)]:
739
- managers = []
740
-
741
705
  # Construct the new ModelState
742
706
  return cls(
743
707
  model._meta.package_label,
@@ -745,22 +709,8 @@ class ModelState:
745
709
  fields,
746
710
  options,
747
711
  bases,
748
- managers,
749
712
  )
750
713
 
751
- def construct_managers(self):
752
- """Deep-clone the managers using deconstruction."""
753
- # Sort all managers by their creation counter
754
- sorted_managers = sorted(self.managers, key=lambda v: v[1].creation_counter)
755
- for mgr_name, manager in sorted_managers:
756
- as_manager, manager_path, qs_path, args, kwargs = manager.deconstruct()
757
- if as_manager:
758
- qs_class = import_string(qs_path)
759
- yield mgr_name, qs_class.as_manager()
760
- else:
761
- manager_class = import_string(manager_path)
762
- yield mgr_name, manager_class(*args, **kwargs)
763
-
764
714
  def clone(self):
765
715
  """Return an exact copy of this ModelState."""
766
716
  return self.__class__(
@@ -772,7 +722,6 @@ class ModelState:
772
722
  # than mutating it.
773
723
  options=dict(self.options),
774
724
  bases=self.bases,
775
- managers=list(self.managers),
776
725
  )
777
726
 
778
727
  def render(self, models_registry):
@@ -799,8 +748,6 @@ class ModelState:
799
748
  body["Meta"] = meta
800
749
  body["__module__"] = "__fake__"
801
750
 
802
- # Restore managers
803
- body.update(self.construct_managers())
804
751
  # Then, make a Model object (models_registry.register_model is called in __new__)
805
752
  model_class = type(self.name, bases, body)
806
753
  from plain.models import register_model
@@ -840,5 +787,4 @@ class ModelState:
840
787
  )
841
788
  and (self.options == other.options)
842
789
  and (self.bases == other.bases)
843
- and (self.managers == other.managers)
844
790
  )
plain/models/options.py CHANGED
@@ -1,5 +1,4 @@
1
1
  import bisect
2
- import copy
3
2
  import inspect
4
3
  from collections import defaultdict
5
4
  from functools import cached_property
@@ -9,7 +8,7 @@ from plain.models import models_registry
9
8
  from plain.models.constraints import UniqueConstraint
10
9
  from plain.models.db import db_connection
11
10
  from plain.models.fields import PrimaryKeyField
12
- from plain.models.manager import Manager
11
+ from plain.models.query import QuerySet
13
12
  from plain.utils.datastructures import ImmutableList
14
13
 
15
14
  PROXY_PARENTS = object()
@@ -24,14 +23,12 @@ IMMUTABLE_WARNING = (
24
23
  DEFAULT_NAMES = (
25
24
  "db_table",
26
25
  "db_table_comment",
26
+ "queryset_class",
27
27
  "ordering",
28
28
  "package_label",
29
29
  "models_registry",
30
- "default_related_name",
31
30
  "required_db_features",
32
31
  "required_db_vendor",
33
- "base_manager_name",
34
- "default_manager_name",
35
32
  "indexes",
36
33
  "constraints",
37
34
  )
@@ -49,10 +46,8 @@ class Options:
49
46
  "local_concrete_fields",
50
47
  "_non_pk_concrete_field_names",
51
48
  "_forward_fields_map",
52
- "managers",
53
- "managers_map",
54
- "base_manager",
55
- "default_manager",
49
+ "base_queryset",
50
+ "queryset",
56
51
  }
57
52
  REVERSE_PROPERTIES = {"related_objects", "fields_map", "_relation_tree"}
58
53
 
@@ -62,9 +57,7 @@ class Options:
62
57
  self._get_fields_cache = {}
63
58
  self.local_fields = []
64
59
  self.local_many_to_many = []
65
- self.local_managers = []
66
- self.base_manager_name = None
67
- self.default_manager_name = None
60
+ self.queryset_class = None
68
61
  self.model_name = None
69
62
  self.db_table = ""
70
63
  self.db_table_comment = ""
@@ -89,8 +82,6 @@ class Options:
89
82
  # A custom app registry to use, if you're making a separate model set.
90
83
  self.models_registry = self.default_models_registry
91
84
 
92
- self.default_related_name = None
93
-
94
85
  @property
95
86
  def label(self):
96
87
  return f"{self.package_label}.{self.object_name}"
@@ -169,10 +160,6 @@ class Options:
169
160
  if not any(f.name == "id" for f in self.local_fields):
170
161
  model.add_to_class("id", PrimaryKeyField())
171
162
 
172
- def add_manager(self, manager):
173
- self.local_managers.append(manager)
174
- self._expire_cache()
175
-
176
163
  def add_field(self, field, private=False):
177
164
  # Insert the given field in the order in which it was created, using
178
165
  # the "creation_counter" attribute of the field.
@@ -224,75 +211,25 @@ class Options:
224
211
  )
225
212
  return True
226
213
 
227
- @cached_property
228
- def managers(self):
229
- managers = []
230
- seen_managers = set()
231
- bases = (b for b in self.model.mro() if hasattr(b, "_meta"))
232
- for depth, base in enumerate(bases):
233
- for manager in base._meta.local_managers:
234
- if manager.name in seen_managers:
235
- continue
236
-
237
- manager = copy.copy(manager)
238
- manager.model = self.model
239
- seen_managers.add(manager.name)
240
- managers.append((depth, manager.creation_counter, manager))
241
-
242
- return make_immutable_fields_list(
243
- "managers",
244
- (m[2] for m in sorted(managers)),
245
- )
246
-
247
- @cached_property
248
- def managers_map(self):
249
- return {manager.name: manager for manager in self.managers}
250
-
251
- @cached_property
252
- def base_manager(self):
253
- base_manager_name = self.base_manager_name
254
- if not base_manager_name:
255
- # Get the first parent's base_manager_name if there's one.
256
- for parent in self.model.mro()[1:]:
257
- if hasattr(parent, "_meta"):
258
- if parent._base_manager.name != "_base_manager":
259
- base_manager_name = parent._base_manager.name
260
- break
261
-
262
- if base_manager_name:
263
- try:
264
- return self.managers_map[base_manager_name]
265
- except KeyError:
266
- raise ValueError(
267
- f"{self.object_name} has no manager named {base_manager_name!r}"
268
- )
269
-
270
- manager = Manager()
271
- manager.name = "_base_manager"
272
- manager.model = self.model
273
- manager.auto_created = True
274
- return manager
275
-
276
- @cached_property
277
- def default_manager(self):
278
- default_manager_name = self.default_manager_name
279
- if not default_manager_name and not self.local_managers:
280
- # Get the first parent's default_manager_name if there's one.
281
- for parent in self.model.mro()[1:]:
282
- if hasattr(parent, "_meta"):
283
- default_manager_name = parent._meta.default_manager_name
284
- break
285
-
286
- if default_manager_name:
287
- try:
288
- return self.managers_map[default_manager_name]
289
- except KeyError:
290
- raise ValueError(
291
- f"{self.object_name} has no manager named {default_manager_name!r}"
292
- )
214
+ @property
215
+ def base_queryset(self):
216
+ """
217
+ The base queryset is used by Plain's internal operations like cascading
218
+ deletes, migrations, and related object lookups. It provides access to
219
+ all objects in the database without any filtering, ensuring Plain can
220
+ always see the complete dataset when performing framework operations.
221
+
222
+ Unlike user-defined querysets which may filter results (e.g. only active
223
+ objects), the base queryset must never filter out rows to prevent
224
+ incomplete results in related queries.
225
+ """
226
+ return QuerySet(model=self.model)
293
227
 
294
- if self.managers:
295
- return self.managers[0]
228
+ @property
229
+ def queryset(self):
230
+ if self.queryset_class:
231
+ return self.queryset_class(model=self.model)
232
+ return QuerySet(model=self.model)
296
233
 
297
234
  @cached_property
298
235
  def fields(self):