plain.models 0.49.2__py3-none-any.whl → 0.51.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.
- plain/models/CHANGELOG.md +27 -0
- plain/models/README.md +26 -42
- plain/models/__init__.py +2 -0
- plain/models/aggregates.py +42 -19
- plain/models/backends/base/base.py +125 -105
- plain/models/backends/base/client.py +11 -3
- plain/models/backends/base/creation.py +24 -14
- plain/models/backends/base/features.py +10 -4
- plain/models/backends/base/introspection.py +37 -20
- plain/models/backends/base/operations.py +187 -91
- plain/models/backends/base/schema.py +338 -218
- plain/models/backends/base/validation.py +13 -4
- plain/models/backends/ddl_references.py +85 -43
- plain/models/backends/mysql/base.py +29 -26
- plain/models/backends/mysql/client.py +7 -2
- plain/models/backends/mysql/compiler.py +13 -4
- plain/models/backends/mysql/creation.py +5 -2
- plain/models/backends/mysql/features.py +24 -22
- plain/models/backends/mysql/introspection.py +22 -13
- plain/models/backends/mysql/operations.py +107 -40
- plain/models/backends/mysql/schema.py +52 -28
- plain/models/backends/mysql/validation.py +13 -6
- plain/models/backends/postgresql/base.py +41 -34
- plain/models/backends/postgresql/client.py +7 -2
- plain/models/backends/postgresql/creation.py +10 -5
- plain/models/backends/postgresql/introspection.py +15 -8
- plain/models/backends/postgresql/operations.py +110 -43
- plain/models/backends/postgresql/schema.py +88 -49
- plain/models/backends/sqlite3/_functions.py +151 -115
- plain/models/backends/sqlite3/base.py +37 -23
- plain/models/backends/sqlite3/client.py +7 -1
- plain/models/backends/sqlite3/creation.py +9 -5
- plain/models/backends/sqlite3/features.py +5 -3
- plain/models/backends/sqlite3/introspection.py +32 -16
- plain/models/backends/sqlite3/operations.py +126 -43
- plain/models/backends/sqlite3/schema.py +127 -92
- plain/models/backends/utils.py +52 -29
- plain/models/backups/cli.py +8 -6
- plain/models/backups/clients.py +16 -7
- plain/models/backups/core.py +24 -13
- plain/models/base.py +221 -229
- plain/models/cli.py +98 -67
- plain/models/config.py +1 -1
- plain/models/connections.py +23 -7
- plain/models/constraints.py +79 -56
- plain/models/database_url.py +1 -1
- plain/models/db.py +6 -2
- plain/models/deletion.py +80 -56
- plain/models/entrypoints.py +1 -1
- plain/models/enums.py +22 -11
- plain/models/exceptions.py +23 -8
- plain/models/expressions.py +441 -258
- plain/models/fields/__init__.py +272 -217
- plain/models/fields/json.py +123 -57
- plain/models/fields/mixins.py +12 -8
- plain/models/fields/related.py +324 -290
- plain/models/fields/related_descriptors.py +33 -24
- plain/models/fields/related_lookups.py +24 -12
- plain/models/fields/related_managers.py +102 -79
- plain/models/fields/reverse_related.py +66 -63
- plain/models/forms.py +101 -75
- plain/models/functions/comparison.py +71 -18
- plain/models/functions/datetime.py +79 -29
- plain/models/functions/math.py +43 -10
- plain/models/functions/mixins.py +24 -7
- plain/models/functions/text.py +104 -25
- plain/models/functions/window.py +12 -6
- plain/models/indexes.py +57 -32
- plain/models/lookups.py +228 -153
- plain/models/meta.py +505 -0
- plain/models/migrations/autodetector.py +86 -43
- plain/models/migrations/exceptions.py +7 -3
- plain/models/migrations/executor.py +33 -7
- plain/models/migrations/graph.py +79 -50
- plain/models/migrations/loader.py +45 -22
- plain/models/migrations/migration.py +23 -18
- plain/models/migrations/operations/base.py +38 -20
- plain/models/migrations/operations/fields.py +95 -48
- plain/models/migrations/operations/models.py +246 -142
- plain/models/migrations/operations/special.py +82 -25
- plain/models/migrations/optimizer.py +7 -2
- plain/models/migrations/questioner.py +58 -31
- plain/models/migrations/recorder.py +27 -16
- plain/models/migrations/serializer.py +50 -39
- plain/models/migrations/state.py +232 -156
- plain/models/migrations/utils.py +30 -14
- plain/models/migrations/writer.py +17 -14
- plain/models/options.py +189 -518
- plain/models/otel.py +16 -6
- plain/models/preflight.py +42 -17
- plain/models/query.py +400 -251
- plain/models/query_utils.py +109 -69
- plain/models/registry.py +40 -21
- plain/models/sql/compiler.py +190 -127
- plain/models/sql/datastructures.py +38 -25
- plain/models/sql/query.py +320 -225
- plain/models/sql/subqueries.py +36 -25
- plain/models/sql/where.py +54 -29
- plain/models/test/pytest.py +15 -11
- plain/models/test/utils.py +4 -2
- plain/models/transaction.py +20 -7
- plain/models/utils.py +17 -6
- {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/METADATA +27 -43
- plain_models-0.51.0.dist-info/RECORD +123 -0
- plain_models-0.49.2.dist-info/RECORD +0 -122
- {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/WHEEL +0 -0
- {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/entry_points.txt +0 -0
- {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,14 +1,23 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
from functools import cached_property
|
4
|
+
from typing import TYPE_CHECKING, Any
|
2
5
|
|
3
6
|
from plain import models
|
7
|
+
from plain.models.base import ModelBase
|
4
8
|
from plain.models.migrations.operations.base import Operation
|
5
9
|
from plain.models.migrations.state import ModelState
|
6
10
|
from plain.models.migrations.utils import field_references, resolve_relation
|
7
11
|
|
8
12
|
from .fields import AddField, AlterField, FieldOperation, RemoveField, RenameField
|
9
13
|
|
14
|
+
if TYPE_CHECKING:
|
15
|
+
from plain.models.backends.base.schema import BaseDatabaseSchemaEditor
|
16
|
+
from plain.models.fields import Field
|
17
|
+
from plain.models.migrations.state import ProjectState
|
18
|
+
|
10
19
|
|
11
|
-
def _check_for_duplicates(arg_name, objs):
|
20
|
+
def _check_for_duplicates(arg_name: str, objs: Any) -> None:
|
12
21
|
used_vals = set()
|
13
22
|
for val in objs:
|
14
23
|
if val in used_vals:
|
@@ -19,22 +28,24 @@ def _check_for_duplicates(arg_name, objs):
|
|
19
28
|
|
20
29
|
|
21
30
|
class ModelOperation(Operation):
|
22
|
-
def __init__(self, name):
|
31
|
+
def __init__(self, name: str) -> None:
|
23
32
|
self.name = name
|
24
33
|
|
25
34
|
@cached_property
|
26
|
-
def name_lower(self):
|
35
|
+
def name_lower(self) -> str:
|
27
36
|
return self.name.lower()
|
28
37
|
|
29
|
-
def references_model(self, name, package_label):
|
38
|
+
def references_model(self, name: str, package_label: str) -> bool:
|
30
39
|
return name.lower() == self.name_lower
|
31
40
|
|
32
|
-
def reduce(
|
33
|
-
|
41
|
+
def reduce(
|
42
|
+
self, operation: Operation, package_label: str
|
43
|
+
) -> bool | list[Operation]:
|
44
|
+
return super().reduce(operation, package_label) or self.can_reduce_through( # type: ignore[misc]
|
34
45
|
operation, package_label
|
35
46
|
)
|
36
47
|
|
37
|
-
def can_reduce_through(self, operation, package_label):
|
48
|
+
def can_reduce_through(self, operation: Operation, package_label: str) -> bool:
|
38
49
|
return not operation.references_model(self.name, package_label)
|
39
50
|
|
40
51
|
|
@@ -43,7 +54,13 @@ class CreateModel(ModelOperation):
|
|
43
54
|
|
44
55
|
serialization_expand_args = ["fields", "options"]
|
45
56
|
|
46
|
-
def __init__(
|
57
|
+
def __init__(
|
58
|
+
self,
|
59
|
+
name: str,
|
60
|
+
fields: list[tuple[str, Field]],
|
61
|
+
options: dict[str, Any] | None = None,
|
62
|
+
bases: tuple[Any, ...] | None = None,
|
63
|
+
) -> None:
|
47
64
|
self.fields = fields
|
48
65
|
self.options = options or {}
|
49
66
|
self.bases = bases or (models.Model,)
|
@@ -53,8 +70,10 @@ class CreateModel(ModelOperation):
|
|
53
70
|
_check_for_duplicates(
|
54
71
|
"bases",
|
55
72
|
(
|
56
|
-
base.
|
57
|
-
if
|
73
|
+
base.model_options.label_lower
|
74
|
+
if not isinstance(base, str)
|
75
|
+
and base is not models.Model
|
76
|
+
and hasattr(base, "_model_meta")
|
58
77
|
else base.lower()
|
59
78
|
if isinstance(base, str)
|
60
79
|
else base
|
@@ -62,8 +81,8 @@ class CreateModel(ModelOperation):
|
|
62
81
|
),
|
63
82
|
)
|
64
83
|
|
65
|
-
def deconstruct(self):
|
66
|
-
kwargs = {
|
84
|
+
def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
|
85
|
+
kwargs: dict[str, Any] = {
|
67
86
|
"name": self.name,
|
68
87
|
"fields": self.fields,
|
69
88
|
}
|
@@ -73,7 +92,7 @@ class CreateModel(ModelOperation):
|
|
73
92
|
kwargs["bases"] = self.bases
|
74
93
|
return (self.__class__.__qualname__, [], kwargs)
|
75
94
|
|
76
|
-
def state_forwards(self, package_label, state):
|
95
|
+
def state_forwards(self, package_label: str, state: ProjectState) -> None:
|
77
96
|
state.add_model(
|
78
97
|
ModelState(
|
79
98
|
package_label,
|
@@ -84,19 +103,25 @@ class CreateModel(ModelOperation):
|
|
84
103
|
)
|
85
104
|
)
|
86
105
|
|
87
|
-
def database_forwards(
|
88
|
-
|
106
|
+
def database_forwards(
|
107
|
+
self,
|
108
|
+
package_label: str,
|
109
|
+
schema_editor: BaseDatabaseSchemaEditor,
|
110
|
+
from_state: ProjectState,
|
111
|
+
to_state: ProjectState,
|
112
|
+
) -> None:
|
113
|
+
model = to_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
|
89
114
|
if self.allow_migrate_model(schema_editor.connection, model):
|
90
115
|
schema_editor.create_model(model)
|
91
116
|
|
92
|
-
def describe(self):
|
117
|
+
def describe(self) -> str:
|
93
118
|
return f"Create model {self.name}"
|
94
119
|
|
95
120
|
@property
|
96
|
-
def migration_name_fragment(self):
|
121
|
+
def migration_name_fragment(self) -> str:
|
97
122
|
return self.name_lower
|
98
123
|
|
99
|
-
def references_model(self, name, package_label):
|
124
|
+
def references_model(self, name: str, package_label: str) -> bool:
|
100
125
|
name_lower = name.lower()
|
101
126
|
if name_lower == self.name_lower:
|
102
127
|
return True
|
@@ -106,7 +131,7 @@ class CreateModel(ModelOperation):
|
|
106
131
|
for base in self.bases:
|
107
132
|
if (
|
108
133
|
base is not models.Model
|
109
|
-
and isinstance(base,
|
134
|
+
and isinstance(base, ModelBase | str)
|
110
135
|
and resolve_relation(base, package_label) == reference_model_tuple
|
111
136
|
):
|
112
137
|
return True
|
@@ -119,7 +144,9 @@ class CreateModel(ModelOperation):
|
|
119
144
|
return True
|
120
145
|
return False
|
121
146
|
|
122
|
-
def reduce(
|
147
|
+
def reduce(
|
148
|
+
self, operation: Operation, package_label: str
|
149
|
+
) -> bool | list[Operation]:
|
123
150
|
if (
|
124
151
|
isinstance(operation, DeleteModel)
|
125
152
|
and self.name_lower == operation.name_lower
|
@@ -213,104 +240,118 @@ class CreateModel(ModelOperation):
|
|
213
240
|
class DeleteModel(ModelOperation):
|
214
241
|
"""Drop a model's table."""
|
215
242
|
|
216
|
-
def deconstruct(self):
|
217
|
-
kwargs = {
|
243
|
+
def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
|
244
|
+
kwargs: dict[str, Any] = {
|
218
245
|
"name": self.name,
|
219
246
|
}
|
220
247
|
return (self.__class__.__qualname__, [], kwargs)
|
221
248
|
|
222
|
-
def state_forwards(self, package_label, state):
|
249
|
+
def state_forwards(self, package_label: str, state: ProjectState) -> None:
|
223
250
|
state.remove_model(package_label, self.name_lower)
|
224
251
|
|
225
|
-
def database_forwards(
|
226
|
-
|
252
|
+
def database_forwards(
|
253
|
+
self,
|
254
|
+
package_label: str,
|
255
|
+
schema_editor: BaseDatabaseSchemaEditor,
|
256
|
+
from_state: ProjectState,
|
257
|
+
to_state: ProjectState,
|
258
|
+
) -> None:
|
259
|
+
model = from_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
|
227
260
|
if self.allow_migrate_model(schema_editor.connection, model):
|
228
261
|
schema_editor.delete_model(model)
|
229
262
|
|
230
|
-
def references_model(self, name, package_label):
|
263
|
+
def references_model(self, name: str, package_label: str) -> bool:
|
231
264
|
# The deleted model could be referencing the specified model through
|
232
265
|
# related fields.
|
233
266
|
return True
|
234
267
|
|
235
|
-
def describe(self):
|
268
|
+
def describe(self) -> str:
|
236
269
|
return f"Delete model {self.name}"
|
237
270
|
|
238
271
|
@property
|
239
|
-
def migration_name_fragment(self):
|
272
|
+
def migration_name_fragment(self) -> str:
|
240
273
|
return f"delete_{self.name_lower}"
|
241
274
|
|
242
275
|
|
243
276
|
class RenameModel(ModelOperation):
|
244
277
|
"""Rename a model."""
|
245
278
|
|
246
|
-
def __init__(self, old_name, new_name):
|
279
|
+
def __init__(self, old_name: str, new_name: str) -> None:
|
247
280
|
self.old_name = old_name
|
248
281
|
self.new_name = new_name
|
249
282
|
super().__init__(old_name)
|
250
283
|
|
251
284
|
@cached_property
|
252
|
-
def old_name_lower(self):
|
285
|
+
def old_name_lower(self) -> str:
|
253
286
|
return self.old_name.lower()
|
254
287
|
|
255
288
|
@cached_property
|
256
|
-
def new_name_lower(self):
|
289
|
+
def new_name_lower(self) -> str:
|
257
290
|
return self.new_name.lower()
|
258
291
|
|
259
|
-
def deconstruct(self):
|
260
|
-
kwargs = {
|
292
|
+
def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
|
293
|
+
kwargs: dict[str, Any] = {
|
261
294
|
"old_name": self.old_name,
|
262
295
|
"new_name": self.new_name,
|
263
296
|
}
|
264
297
|
return (self.__class__.__qualname__, [], kwargs)
|
265
298
|
|
266
|
-
def state_forwards(self, package_label, state):
|
299
|
+
def state_forwards(self, package_label: str, state: ProjectState) -> None:
|
267
300
|
state.rename_model(package_label, self.old_name, self.new_name)
|
268
301
|
|
269
|
-
def database_forwards(
|
270
|
-
|
302
|
+
def database_forwards(
|
303
|
+
self,
|
304
|
+
package_label: str,
|
305
|
+
schema_editor: BaseDatabaseSchemaEditor,
|
306
|
+
from_state: ProjectState,
|
307
|
+
to_state: ProjectState,
|
308
|
+
) -> None:
|
309
|
+
new_model = to_state.models_registry.get_model(package_label, self.new_name) # type: ignore[attr-defined]
|
271
310
|
if self.allow_migrate_model(schema_editor.connection, new_model):
|
272
|
-
old_model = from_state.models_registry.get_model(
|
311
|
+
old_model = from_state.models_registry.get_model( # type: ignore[attr-defined]
|
273
312
|
package_label, self.old_name
|
274
313
|
)
|
275
314
|
# Move the main table
|
276
315
|
schema_editor.alter_db_table(
|
277
316
|
new_model,
|
278
|
-
old_model.
|
279
|
-
new_model.
|
317
|
+
old_model.model_options.db_table,
|
318
|
+
new_model.model_options.db_table,
|
280
319
|
)
|
281
320
|
# Alter the fields pointing to us
|
282
|
-
for related_object in old_model.
|
283
|
-
if related_object.related_model == old_model:
|
321
|
+
for related_object in old_model._model_meta.related_objects:
|
322
|
+
if related_object.related_model == old_model: # type: ignore[attr-defined]
|
284
323
|
model = new_model
|
285
324
|
related_key = (package_label, self.new_name_lower)
|
286
325
|
else:
|
287
|
-
model = related_object.related_model
|
326
|
+
model = related_object.related_model # type: ignore[attr-defined]
|
288
327
|
related_key = (
|
289
|
-
related_object.related_model.
|
290
|
-
related_object.related_model.
|
328
|
+
related_object.related_model.model_options.package_label,
|
329
|
+
related_object.related_model.model_options.model_name,
|
291
330
|
)
|
292
331
|
to_field = to_state.models_registry.get_model(
|
293
332
|
*related_key
|
294
|
-
).
|
333
|
+
)._model_meta.get_field(related_object.field.name)
|
295
334
|
schema_editor.alter_field(
|
296
335
|
model,
|
297
336
|
related_object.field,
|
298
337
|
to_field,
|
299
338
|
)
|
300
339
|
|
301
|
-
def references_model(self, name, package_label):
|
340
|
+
def references_model(self, name: str, package_label: str) -> bool:
|
302
341
|
return (
|
303
342
|
name.lower() == self.old_name_lower or name.lower() == self.new_name_lower
|
304
343
|
)
|
305
344
|
|
306
|
-
def describe(self):
|
345
|
+
def describe(self) -> str:
|
307
346
|
return f"Rename model {self.old_name} to {self.new_name}"
|
308
347
|
|
309
348
|
@property
|
310
|
-
def migration_name_fragment(self):
|
349
|
+
def migration_name_fragment(self) -> str:
|
311
350
|
return f"rename_{self.old_name_lower}_{self.new_name_lower}"
|
312
351
|
|
313
|
-
def reduce(
|
352
|
+
def reduce(
|
353
|
+
self, operation: Operation, package_label: str
|
354
|
+
) -> bool | list[Operation]:
|
314
355
|
if (
|
315
356
|
isinstance(operation, RenameModel)
|
316
357
|
and self.new_name_lower == operation.old_name_lower
|
@@ -323,13 +364,15 @@ class RenameModel(ModelOperation):
|
|
323
364
|
]
|
324
365
|
# Skip `ModelOperation.reduce` as we want to run `references_model`
|
325
366
|
# against self.new_name.
|
326
|
-
return super(ModelOperation, self).reduce(
|
367
|
+
return super(ModelOperation, self).reduce( # type: ignore[misc]
|
327
368
|
operation, package_label
|
328
369
|
) or not operation.references_model(self.new_name, package_label)
|
329
370
|
|
330
371
|
|
331
372
|
class ModelOptionOperation(ModelOperation):
|
332
|
-
def reduce(
|
373
|
+
def reduce(
|
374
|
+
self, operation: Operation, package_label: str
|
375
|
+
) -> bool | list[Operation]:
|
333
376
|
if (
|
334
377
|
isinstance(operation, self.__class__ | DeleteModel)
|
335
378
|
and self.name_lower == operation.name_lower
|
@@ -341,75 +384,87 @@ class ModelOptionOperation(ModelOperation):
|
|
341
384
|
class AlterModelTable(ModelOptionOperation):
|
342
385
|
"""Rename a model's table."""
|
343
386
|
|
344
|
-
def __init__(self, name, table):
|
387
|
+
def __init__(self, name: str, table: str | None) -> None:
|
345
388
|
self.table = table
|
346
389
|
super().__init__(name)
|
347
390
|
|
348
|
-
def deconstruct(self):
|
349
|
-
kwargs = {
|
391
|
+
def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
|
392
|
+
kwargs: dict[str, Any] = {
|
350
393
|
"name": self.name,
|
351
394
|
"table": self.table,
|
352
395
|
}
|
353
396
|
return (self.__class__.__qualname__, [], kwargs)
|
354
397
|
|
355
|
-
def state_forwards(self, package_label, state):
|
398
|
+
def state_forwards(self, package_label: str, state: ProjectState) -> None:
|
356
399
|
state.alter_model_options(
|
357
400
|
package_label, self.name_lower, {"db_table": self.table}
|
358
401
|
)
|
359
402
|
|
360
|
-
def database_forwards(
|
361
|
-
|
403
|
+
def database_forwards(
|
404
|
+
self,
|
405
|
+
package_label: str,
|
406
|
+
schema_editor: BaseDatabaseSchemaEditor,
|
407
|
+
from_state: ProjectState,
|
408
|
+
to_state: ProjectState,
|
409
|
+
) -> None:
|
410
|
+
new_model = to_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
|
362
411
|
if self.allow_migrate_model(schema_editor.connection, new_model):
|
363
|
-
old_model = from_state.models_registry.get_model(package_label, self.name)
|
412
|
+
old_model = from_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
|
364
413
|
schema_editor.alter_db_table(
|
365
414
|
new_model,
|
366
|
-
old_model.
|
367
|
-
new_model.
|
415
|
+
old_model.model_options.db_table,
|
416
|
+
new_model.model_options.db_table,
|
368
417
|
)
|
369
418
|
|
370
|
-
def describe(self):
|
419
|
+
def describe(self) -> str:
|
371
420
|
return "Rename table for {} to {}".format(
|
372
421
|
self.name,
|
373
422
|
self.table if self.table is not None else "(default)",
|
374
423
|
)
|
375
424
|
|
376
425
|
@property
|
377
|
-
def migration_name_fragment(self):
|
426
|
+
def migration_name_fragment(self) -> str:
|
378
427
|
return f"alter_{self.name_lower}_table"
|
379
428
|
|
380
429
|
|
381
430
|
class AlterModelTableComment(ModelOptionOperation):
|
382
|
-
def __init__(self, name, table_comment):
|
431
|
+
def __init__(self, name: str, table_comment: str | None) -> None:
|
383
432
|
self.table_comment = table_comment
|
384
433
|
super().__init__(name)
|
385
434
|
|
386
|
-
def deconstruct(self):
|
387
|
-
kwargs = {
|
435
|
+
def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
|
436
|
+
kwargs: dict[str, Any] = {
|
388
437
|
"name": self.name,
|
389
438
|
"table_comment": self.table_comment,
|
390
439
|
}
|
391
440
|
return (self.__class__.__qualname__, [], kwargs)
|
392
441
|
|
393
|
-
def state_forwards(self, package_label, state):
|
442
|
+
def state_forwards(self, package_label: str, state: ProjectState) -> None:
|
394
443
|
state.alter_model_options(
|
395
444
|
package_label, self.name_lower, {"db_table_comment": self.table_comment}
|
396
445
|
)
|
397
446
|
|
398
|
-
def database_forwards(
|
399
|
-
|
447
|
+
def database_forwards(
|
448
|
+
self,
|
449
|
+
package_label: str,
|
450
|
+
schema_editor: BaseDatabaseSchemaEditor,
|
451
|
+
from_state: ProjectState,
|
452
|
+
to_state: ProjectState,
|
453
|
+
) -> None:
|
454
|
+
new_model = to_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
|
400
455
|
if self.allow_migrate_model(schema_editor.connection, new_model):
|
401
|
-
old_model = from_state.models_registry.get_model(package_label, self.name)
|
456
|
+
old_model = from_state.models_registry.get_model(package_label, self.name) # type: ignore[attr-defined]
|
402
457
|
schema_editor.alter_db_table_comment(
|
403
458
|
new_model,
|
404
|
-
old_model.
|
405
|
-
new_model.
|
459
|
+
old_model.model_options.db_table_comment,
|
460
|
+
new_model.model_options.db_table_comment,
|
406
461
|
)
|
407
462
|
|
408
|
-
def describe(self):
|
463
|
+
def describe(self) -> str:
|
409
464
|
return f"Alter {self.name} table comment"
|
410
465
|
|
411
466
|
@property
|
412
|
-
def migration_name_fragment(self):
|
467
|
+
def migration_name_fragment(self) -> str:
|
413
468
|
return f"alter_{self.name_lower}_table_comment"
|
414
469
|
|
415
470
|
|
@@ -425,18 +480,18 @@ class AlterModelOptions(ModelOptionOperation):
|
|
425
480
|
"ordering",
|
426
481
|
]
|
427
482
|
|
428
|
-
def __init__(self, name, options):
|
483
|
+
def __init__(self, name: str, options: dict[str, Any]) -> None:
|
429
484
|
self.options = options
|
430
485
|
super().__init__(name)
|
431
486
|
|
432
|
-
def deconstruct(self):
|
433
|
-
kwargs = {
|
487
|
+
def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
|
488
|
+
kwargs: dict[str, Any] = {
|
434
489
|
"name": self.name,
|
435
490
|
"options": self.options,
|
436
491
|
}
|
437
492
|
return (self.__class__.__qualname__, [], kwargs)
|
438
493
|
|
439
|
-
def state_forwards(self, package_label, state):
|
494
|
+
def state_forwards(self, package_label: str, state: ProjectState) -> None:
|
440
495
|
state.alter_model_options(
|
441
496
|
package_label,
|
442
497
|
self.name_lower,
|
@@ -444,14 +499,20 @@ class AlterModelOptions(ModelOptionOperation):
|
|
444
499
|
self.ALTER_OPTION_KEYS,
|
445
500
|
)
|
446
501
|
|
447
|
-
def database_forwards(
|
502
|
+
def database_forwards(
|
503
|
+
self,
|
504
|
+
package_label: str,
|
505
|
+
schema_editor: BaseDatabaseSchemaEditor,
|
506
|
+
from_state: ProjectState,
|
507
|
+
to_state: ProjectState,
|
508
|
+
) -> None:
|
448
509
|
pass
|
449
510
|
|
450
|
-
def describe(self):
|
511
|
+
def describe(self) -> str:
|
451
512
|
return f"Change Meta options on {self.name}"
|
452
513
|
|
453
514
|
@property
|
454
|
-
def migration_name_fragment(self):
|
515
|
+
def migration_name_fragment(self) -> str:
|
455
516
|
return f"alter_{self.name_lower}_options"
|
456
517
|
|
457
518
|
|
@@ -459,32 +520,38 @@ class IndexOperation(Operation):
|
|
459
520
|
option_name = "indexes"
|
460
521
|
|
461
522
|
@cached_property
|
462
|
-
def model_name_lower(self):
|
463
|
-
return self.model_name.lower()
|
523
|
+
def model_name_lower(self) -> str:
|
524
|
+
return self.model_name.lower() # type: ignore[attr-defined]
|
464
525
|
|
465
526
|
|
466
527
|
class AddIndex(IndexOperation):
|
467
528
|
"""Add an index on a model."""
|
468
529
|
|
469
|
-
def __init__(self, model_name, index):
|
530
|
+
def __init__(self, model_name: str, index: Any) -> None:
|
470
531
|
self.model_name = model_name
|
471
|
-
if not index.name:
|
532
|
+
if not index.name: # type: ignore[attr-defined]
|
472
533
|
raise ValueError(
|
473
534
|
"Indexes passed to AddIndex operations require a name "
|
474
535
|
f"argument. {index!r} doesn't have one."
|
475
536
|
)
|
476
537
|
self.index = index
|
477
538
|
|
478
|
-
def state_forwards(self, package_label, state):
|
539
|
+
def state_forwards(self, package_label: str, state: ProjectState) -> None:
|
479
540
|
state.add_index(package_label, self.model_name_lower, self.index)
|
480
541
|
|
481
|
-
def database_forwards(
|
482
|
-
|
542
|
+
def database_forwards(
|
543
|
+
self,
|
544
|
+
package_label: str,
|
545
|
+
schema_editor: BaseDatabaseSchemaEditor,
|
546
|
+
from_state: ProjectState,
|
547
|
+
to_state: ProjectState,
|
548
|
+
) -> None:
|
549
|
+
model = to_state.models_registry.get_model(package_label, self.model_name) # type: ignore[attr-defined]
|
483
550
|
if self.allow_migrate_model(schema_editor.connection, model):
|
484
551
|
schema_editor.add_index(model, self.index)
|
485
552
|
|
486
|
-
def deconstruct(self):
|
487
|
-
kwargs = {
|
553
|
+
def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
|
554
|
+
kwargs: dict[str, Any] = {
|
488
555
|
"model_name": self.model_name,
|
489
556
|
"index": self.index,
|
490
557
|
}
|
@@ -494,43 +561,49 @@ class AddIndex(IndexOperation):
|
|
494
561
|
kwargs,
|
495
562
|
)
|
496
563
|
|
497
|
-
def describe(self):
|
498
|
-
if self.index.expressions:
|
564
|
+
def describe(self) -> str:
|
565
|
+
if self.index.expressions: # type: ignore[attr-defined]
|
499
566
|
return "Create index {} on {} on model {}".format(
|
500
|
-
self.index.name,
|
501
|
-
", ".join([str(expression) for expression in self.index.expressions]),
|
567
|
+
self.index.name, # type: ignore[attr-defined]
|
568
|
+
", ".join([str(expression) for expression in self.index.expressions]), # type: ignore[attr-defined]
|
502
569
|
self.model_name,
|
503
570
|
)
|
504
571
|
return "Create index {} on field(s) {} of model {}".format(
|
505
|
-
self.index.name,
|
506
|
-
", ".join(self.index.fields),
|
572
|
+
self.index.name, # type: ignore[attr-defined]
|
573
|
+
", ".join(self.index.fields), # type: ignore[attr-defined]
|
507
574
|
self.model_name,
|
508
575
|
)
|
509
576
|
|
510
577
|
@property
|
511
|
-
def migration_name_fragment(self):
|
512
|
-
return f"{self.model_name_lower}_{self.index.name.lower()}"
|
578
|
+
def migration_name_fragment(self) -> str:
|
579
|
+
return f"{self.model_name_lower}_{self.index.name.lower()}" # type: ignore[attr-defined]
|
513
580
|
|
514
581
|
|
515
582
|
class RemoveIndex(IndexOperation):
|
516
583
|
"""Remove an index from a model."""
|
517
584
|
|
518
|
-
def __init__(self, model_name, name):
|
585
|
+
def __init__(self, model_name: str, name: str) -> None:
|
519
586
|
self.model_name = model_name
|
520
587
|
self.name = name
|
521
588
|
|
522
|
-
def state_forwards(self, package_label, state):
|
589
|
+
def state_forwards(self, package_label: str, state: ProjectState) -> None:
|
523
590
|
state.remove_index(package_label, self.model_name_lower, self.name)
|
524
591
|
|
525
|
-
def database_forwards(
|
526
|
-
|
592
|
+
def database_forwards(
|
593
|
+
self,
|
594
|
+
package_label: str,
|
595
|
+
schema_editor: BaseDatabaseSchemaEditor,
|
596
|
+
from_state: ProjectState,
|
597
|
+
to_state: ProjectState,
|
598
|
+
) -> None:
|
599
|
+
model = from_state.models_registry.get_model(package_label, self.model_name) # type: ignore[attr-defined]
|
527
600
|
if self.allow_migrate_model(schema_editor.connection, model):
|
528
601
|
from_model_state = from_state.models[package_label, self.model_name_lower]
|
529
602
|
index = from_model_state.get_index_by_name(self.name)
|
530
603
|
schema_editor.remove_index(model, index)
|
531
604
|
|
532
|
-
def deconstruct(self):
|
533
|
-
kwargs = {
|
605
|
+
def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
|
606
|
+
kwargs: dict[str, Any] = {
|
534
607
|
"model_name": self.model_name,
|
535
608
|
"name": self.name,
|
536
609
|
}
|
@@ -540,18 +613,24 @@ class RemoveIndex(IndexOperation):
|
|
540
613
|
kwargs,
|
541
614
|
)
|
542
615
|
|
543
|
-
def describe(self):
|
616
|
+
def describe(self) -> str:
|
544
617
|
return f"Remove index {self.name} from {self.model_name}"
|
545
618
|
|
546
619
|
@property
|
547
|
-
def migration_name_fragment(self):
|
620
|
+
def migration_name_fragment(self) -> str:
|
548
621
|
return f"remove_{self.model_name_lower}_{self.name.lower()}"
|
549
622
|
|
550
623
|
|
551
624
|
class RenameIndex(IndexOperation):
|
552
625
|
"""Rename an index."""
|
553
626
|
|
554
|
-
def __init__(
|
627
|
+
def __init__(
|
628
|
+
self,
|
629
|
+
model_name: str,
|
630
|
+
new_name: str,
|
631
|
+
old_name: str | None = None,
|
632
|
+
old_fields: list[str] | tuple[str, ...] | None = None,
|
633
|
+
) -> None:
|
555
634
|
if not old_name and not old_fields:
|
556
635
|
raise ValueError(
|
557
636
|
"RenameIndex requires one of old_name and old_fields arguments to be "
|
@@ -567,15 +646,15 @@ class RenameIndex(IndexOperation):
|
|
567
646
|
self.old_fields = old_fields
|
568
647
|
|
569
648
|
@cached_property
|
570
|
-
def old_name_lower(self):
|
571
|
-
return self.old_name.lower()
|
649
|
+
def old_name_lower(self) -> str:
|
650
|
+
return self.old_name.lower() # type: ignore[union-attr]
|
572
651
|
|
573
652
|
@cached_property
|
574
|
-
def new_name_lower(self):
|
653
|
+
def new_name_lower(self) -> str:
|
575
654
|
return self.new_name.lower()
|
576
655
|
|
577
|
-
def deconstruct(self):
|
578
|
-
kwargs = {
|
656
|
+
def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
|
657
|
+
kwargs: dict[str, Any] = {
|
579
658
|
"model_name": self.model_name,
|
580
659
|
"new_name": self.new_name,
|
581
660
|
}
|
@@ -585,7 +664,7 @@ class RenameIndex(IndexOperation):
|
|
585
664
|
kwargs["old_fields"] = self.old_fields
|
586
665
|
return (self.__class__.__qualname__, [], kwargs)
|
587
666
|
|
588
|
-
def state_forwards(self, package_label, state):
|
667
|
+
def state_forwards(self, package_label: str, state: ProjectState) -> None:
|
589
668
|
if self.old_fields:
|
590
669
|
state.add_index(
|
591
670
|
package_label,
|
@@ -594,20 +673,30 @@ class RenameIndex(IndexOperation):
|
|
594
673
|
)
|
595
674
|
else:
|
596
675
|
state.rename_index(
|
597
|
-
package_label,
|
676
|
+
package_label,
|
677
|
+
self.model_name_lower,
|
678
|
+
self.old_name,
|
679
|
+
self.new_name, # type: ignore[arg-type]
|
598
680
|
)
|
599
681
|
|
600
|
-
def database_forwards(
|
601
|
-
|
682
|
+
def database_forwards(
|
683
|
+
self,
|
684
|
+
package_label: str,
|
685
|
+
schema_editor: BaseDatabaseSchemaEditor,
|
686
|
+
from_state: ProjectState,
|
687
|
+
to_state: ProjectState,
|
688
|
+
) -> None:
|
689
|
+
model = to_state.models_registry.get_model(package_label, self.model_name) # type: ignore[attr-defined]
|
602
690
|
if not self.allow_migrate_model(schema_editor.connection, model):
|
603
|
-
return
|
691
|
+
return None
|
604
692
|
|
605
693
|
if self.old_fields:
|
606
|
-
from_model = from_state.models_registry.get_model(
|
694
|
+
from_model = from_state.models_registry.get_model( # type: ignore[attr-defined]
|
607
695
|
package_label, self.model_name
|
608
696
|
)
|
609
697
|
columns = [
|
610
|
-
from_model.
|
698
|
+
from_model._model_meta.get_field(field).column
|
699
|
+
for field in self.old_fields
|
611
700
|
]
|
612
701
|
matching_index_name = schema_editor._constraint_names(
|
613
702
|
from_model, column_names=columns, index=True
|
@@ -616,7 +705,7 @@ class RenameIndex(IndexOperation):
|
|
616
705
|
raise ValueError(
|
617
706
|
"Found wrong number ({}) of indexes for {}({}).".format(
|
618
707
|
len(matching_index_name),
|
619
|
-
from_model.
|
708
|
+
from_model.model_options.db_table,
|
620
709
|
", ".join(columns),
|
621
710
|
)
|
622
711
|
)
|
@@ -626,16 +715,17 @@ class RenameIndex(IndexOperation):
|
|
626
715
|
)
|
627
716
|
else:
|
628
717
|
from_model_state = from_state.models[package_label, self.model_name_lower]
|
629
|
-
old_index = from_model_state.get_index_by_name(self.old_name)
|
718
|
+
old_index = from_model_state.get_index_by_name(self.old_name) # type: ignore[arg-type]
|
630
719
|
# Don't alter when the index name is not changed.
|
631
|
-
if old_index.name == self.new_name:
|
632
|
-
return
|
720
|
+
if old_index.name == self.new_name: # type: ignore[attr-defined]
|
721
|
+
return None
|
633
722
|
|
634
723
|
to_model_state = to_state.models[package_label, self.model_name_lower]
|
635
724
|
new_index = to_model_state.get_index_by_name(self.new_name)
|
636
725
|
schema_editor.rename_index(model, old_index, new_index)
|
726
|
+
return None
|
637
727
|
|
638
|
-
def describe(self):
|
728
|
+
def describe(self) -> str:
|
639
729
|
if self.old_name:
|
640
730
|
return (
|
641
731
|
f"Rename index {self.old_name} on {self.model_name} to {self.new_name}"
|
@@ -646,16 +736,18 @@ class RenameIndex(IndexOperation):
|
|
646
736
|
)
|
647
737
|
|
648
738
|
@property
|
649
|
-
def migration_name_fragment(self):
|
739
|
+
def migration_name_fragment(self) -> str:
|
650
740
|
if self.old_name:
|
651
741
|
return f"rename_{self.old_name_lower}_{self.new_name_lower}"
|
652
742
|
return "rename_{}_{}_{}".format(
|
653
743
|
self.model_name_lower,
|
654
|
-
"_".join(self.old_fields),
|
744
|
+
"_".join(self.old_fields), # type: ignore[arg-type]
|
655
745
|
self.new_name_lower,
|
656
746
|
)
|
657
747
|
|
658
|
-
def reduce(
|
748
|
+
def reduce(
|
749
|
+
self, operation: Operation, package_label: str
|
750
|
+
) -> bool | list[Operation]:
|
659
751
|
if (
|
660
752
|
isinstance(operation, RenameIndex)
|
661
753
|
and self.model_name_lower == operation.model_name_lower
|
@@ -676,19 +768,25 @@ class RenameIndex(IndexOperation):
|
|
676
768
|
class AddConstraint(IndexOperation):
|
677
769
|
option_name = "constraints"
|
678
770
|
|
679
|
-
def __init__(self, model_name, constraint):
|
771
|
+
def __init__(self, model_name: str, constraint: Any) -> None:
|
680
772
|
self.model_name = model_name
|
681
773
|
self.constraint = constraint
|
682
774
|
|
683
|
-
def state_forwards(self, package_label, state):
|
775
|
+
def state_forwards(self, package_label: str, state: ProjectState) -> None:
|
684
776
|
state.add_constraint(package_label, self.model_name_lower, self.constraint)
|
685
777
|
|
686
|
-
def database_forwards(
|
687
|
-
|
778
|
+
def database_forwards(
|
779
|
+
self,
|
780
|
+
package_label: str,
|
781
|
+
schema_editor: BaseDatabaseSchemaEditor,
|
782
|
+
from_state: ProjectState,
|
783
|
+
to_state: ProjectState,
|
784
|
+
) -> None:
|
785
|
+
model = to_state.models_registry.get_model(package_label, self.model_name) # type: ignore[attr-defined]
|
688
786
|
if self.allow_migrate_model(schema_editor.connection, model):
|
689
787
|
schema_editor.add_constraint(model, self.constraint)
|
690
788
|
|
691
|
-
def deconstruct(self):
|
789
|
+
def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
|
692
790
|
return (
|
693
791
|
self.__class__.__name__,
|
694
792
|
[],
|
@@ -698,32 +796,38 @@ class AddConstraint(IndexOperation):
|
|
698
796
|
},
|
699
797
|
)
|
700
798
|
|
701
|
-
def describe(self):
|
702
|
-
return f"Create constraint {self.constraint.name} on model {self.model_name}"
|
799
|
+
def describe(self) -> str:
|
800
|
+
return f"Create constraint {self.constraint.name} on model {self.model_name}" # type: ignore[attr-defined]
|
703
801
|
|
704
802
|
@property
|
705
|
-
def migration_name_fragment(self):
|
706
|
-
return f"{self.model_name_lower}_{self.constraint.name.lower()}"
|
803
|
+
def migration_name_fragment(self) -> str:
|
804
|
+
return f"{self.model_name_lower}_{self.constraint.name.lower()}" # type: ignore[attr-defined]
|
707
805
|
|
708
806
|
|
709
807
|
class RemoveConstraint(IndexOperation):
|
710
808
|
option_name = "constraints"
|
711
809
|
|
712
|
-
def __init__(self, model_name, name):
|
810
|
+
def __init__(self, model_name: str, name: str) -> None:
|
713
811
|
self.model_name = model_name
|
714
812
|
self.name = name
|
715
813
|
|
716
|
-
def state_forwards(self, package_label, state):
|
814
|
+
def state_forwards(self, package_label: str, state: ProjectState) -> None:
|
717
815
|
state.remove_constraint(package_label, self.model_name_lower, self.name)
|
718
816
|
|
719
|
-
def database_forwards(
|
720
|
-
|
817
|
+
def database_forwards(
|
818
|
+
self,
|
819
|
+
package_label: str,
|
820
|
+
schema_editor: BaseDatabaseSchemaEditor,
|
821
|
+
from_state: ProjectState,
|
822
|
+
to_state: ProjectState,
|
823
|
+
) -> None:
|
824
|
+
model = to_state.models_registry.get_model(package_label, self.model_name) # type: ignore[attr-defined]
|
721
825
|
if self.allow_migrate_model(schema_editor.connection, model):
|
722
826
|
from_model_state = from_state.models[package_label, self.model_name_lower]
|
723
827
|
constraint = from_model_state.get_constraint_by_name(self.name)
|
724
828
|
schema_editor.remove_constraint(model, constraint)
|
725
829
|
|
726
|
-
def deconstruct(self):
|
830
|
+
def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]:
|
727
831
|
return (
|
728
832
|
self.__class__.__name__,
|
729
833
|
[],
|
@@ -733,9 +837,9 @@ class RemoveConstraint(IndexOperation):
|
|
733
837
|
},
|
734
838
|
)
|
735
839
|
|
736
|
-
def describe(self):
|
840
|
+
def describe(self) -> str:
|
737
841
|
return f"Remove constraint {self.name} from model {self.model_name}"
|
738
842
|
|
739
843
|
@property
|
740
|
-
def migration_name_fragment(self):
|
844
|
+
def migration_name_fragment(self) -> str:
|
741
845
|
return f"remove_{self.model_name_lower}_{self.name.lower()}"
|