plain.models 0.49.1__py3-none-any.whl → 0.50.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 +23 -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 +22 -12
- plain/models/backends/base/features.py +10 -4
- plain/models/backends/base/introspection.py +29 -16
- plain/models/backends/base/operations.py +187 -91
- plain/models/backends/base/schema.py +267 -165
- plain/models/backends/base/validation.py +12 -3
- 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 +12 -3
- 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 +106 -39
- plain/models/backends/mysql/schema.py +48 -24
- 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 +109 -42
- plain/models/backends/postgresql/schema.py +85 -46
- 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 +125 -42
- plain/models/backends/sqlite3/schema.py +82 -58
- 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 +113 -74
- plain/models/cli.py +94 -63
- plain/models/config.py +1 -1
- plain/models/connections.py +23 -7
- plain/models/constraints.py +65 -47
- plain/models/database_url.py +1 -1
- plain/models/db.py +6 -2
- plain/models/deletion.py +66 -43
- plain/models/entrypoints.py +1 -1
- plain/models/enums.py +22 -11
- plain/models/exceptions.py +23 -8
- plain/models/expressions.py +440 -257
- plain/models/fields/__init__.py +253 -202
- plain/models/fields/json.py +120 -54
- plain/models/fields/mixins.py +12 -8
- plain/models/fields/related.py +284 -252
- plain/models/fields/related_descriptors.py +34 -25
- plain/models/fields/related_lookups.py +23 -11
- plain/models/fields/related_managers.py +81 -47
- plain/models/fields/reverse_related.py +58 -55
- plain/models/forms.py +89 -63
- 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 +52 -28
- plain/models/lookups.py +228 -153
- 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 +37 -19
- plain/models/migrations/operations/fields.py +89 -42
- plain/models/migrations/operations/models.py +245 -143
- 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 +18 -11
- plain/models/migrations/serializer.py +50 -39
- plain/models/migrations/state.py +220 -133
- plain/models/migrations/utils.py +29 -13
- plain/models/migrations/writer.py +17 -14
- plain/models/options.py +63 -56
- plain/models/otel.py +16 -6
- plain/models/preflight.py +35 -12
- plain/models/query.py +323 -228
- plain/models/query_utils.py +93 -58
- plain/models/registry.py +34 -16
- plain/models/sql/compiler.py +146 -97
- plain/models/sql/datastructures.py +38 -25
- plain/models/sql/query.py +255 -169
- plain/models/sql/subqueries.py +32 -21
- 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 +13 -5
- {plain_models-0.49.1.dist-info → plain_models-0.50.0.dist-info}/METADATA +1 -1
- plain_models-0.50.0.dist-info/RECORD +122 -0
- plain_models-0.49.1.dist-info/RECORD +0 -122
- {plain_models-0.49.1.dist-info → plain_models-0.50.0.dist-info}/WHEEL +0 -0
- {plain_models-0.49.1.dist-info → plain_models-0.50.0.dist-info}/entry_points.txt +0 -0
- {plain_models-0.49.1.dist-info → plain_models-0.50.0.dist-info}/licenses/LICENSE +0 -0
plain/models/base.py
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import copy
|
2
4
|
import inspect
|
3
5
|
import warnings
|
6
|
+
from collections.abc import Iterable, Iterator, Sequence
|
4
7
|
from itertools import chain
|
8
|
+
from typing import Any
|
5
9
|
|
6
10
|
import plain.runtime
|
7
11
|
from plain.exceptions import NON_FIELD_ERRORS, ValidationError
|
@@ -31,10 +35,10 @@ from plain.utils.hashable import make_hashable
|
|
31
35
|
|
32
36
|
|
33
37
|
class Deferred:
|
34
|
-
def __repr__(self):
|
38
|
+
def __repr__(self) -> str:
|
35
39
|
return "<Deferred field>"
|
36
40
|
|
37
|
-
def __str__(self):
|
41
|
+
def __str__(self) -> str:
|
38
42
|
return "<Deferred field>"
|
39
43
|
|
40
44
|
|
@@ -44,7 +48,9 @@ DEFERRED = Deferred()
|
|
44
48
|
class ModelBase(type):
|
45
49
|
"""Metaclass for all models."""
|
46
50
|
|
47
|
-
def __new__(
|
51
|
+
def __new__(
|
52
|
+
cls, name: str, bases: tuple[type, ...], attrs: dict[str, Any], **kwargs: Any
|
53
|
+
) -> type:
|
48
54
|
# Don't do any of this for the root models.Model class.
|
49
55
|
if not bases:
|
50
56
|
return super().__new__(cls, name, bases, attrs)
|
@@ -93,7 +99,7 @@ class ModelBase(type):
|
|
93
99
|
|
94
100
|
return new_class
|
95
101
|
|
96
|
-
def _setup_meta(cls):
|
102
|
+
def _setup_meta(cls) -> None:
|
97
103
|
name = cls.__name__
|
98
104
|
module = cls.__module__
|
99
105
|
|
@@ -123,7 +129,9 @@ class ModelBase(type):
|
|
123
129
|
|
124
130
|
|
125
131
|
class ModelStateFieldsCacheDescriptor:
|
126
|
-
def __get__(
|
132
|
+
def __get__(
|
133
|
+
self, instance: ModelState | None, cls: type | None = None
|
134
|
+
) -> ModelStateFieldsCacheDescriptor | dict[str, Any]:
|
127
135
|
if instance is None:
|
128
136
|
return self
|
129
137
|
res = instance.fields_cache = {}
|
@@ -151,7 +159,7 @@ class Model(metaclass=ModelBase):
|
|
151
159
|
# Every model gets an automatic id field
|
152
160
|
id = PrimaryKeyField()
|
153
161
|
|
154
|
-
def __init__(self, *args, **kwargs):
|
162
|
+
def __init__(self, *args: Any, **kwargs: Any):
|
155
163
|
# Alias some things as locals to avoid repeat global lookups
|
156
164
|
cls = self.__class__
|
157
165
|
opts = self._meta
|
@@ -261,7 +269,7 @@ class Model(metaclass=ModelBase):
|
|
261
269
|
super().__init__()
|
262
270
|
|
263
271
|
@classmethod
|
264
|
-
def from_db(cls, field_names, values):
|
272
|
+
def from_db(cls, field_names: Iterable[str], values: Sequence[Any]) -> Model:
|
265
273
|
if len(values) != len(cls._meta.concrete_fields):
|
266
274
|
values_iter = iter(values)
|
267
275
|
values = [
|
@@ -272,13 +280,13 @@ class Model(metaclass=ModelBase):
|
|
272
280
|
new._state.adding = False
|
273
281
|
return new
|
274
282
|
|
275
|
-
def __repr__(self):
|
283
|
+
def __repr__(self) -> str:
|
276
284
|
return f"<{self.__class__.__name__}: {self}>"
|
277
285
|
|
278
|
-
def __str__(self):
|
286
|
+
def __str__(self) -> str:
|
279
287
|
return f"{self.__class__.__name__} object ({self.id})"
|
280
288
|
|
281
|
-
def __eq__(self, other):
|
289
|
+
def __eq__(self, other: object) -> bool:
|
282
290
|
if not isinstance(other, Model):
|
283
291
|
return NotImplemented
|
284
292
|
if self.__class__ != other.__class__:
|
@@ -288,18 +296,18 @@ class Model(metaclass=ModelBase):
|
|
288
296
|
return self is other
|
289
297
|
return my_id == other.id
|
290
298
|
|
291
|
-
def __hash__(self):
|
299
|
+
def __hash__(self) -> int:
|
292
300
|
if self.id is None:
|
293
301
|
raise TypeError("Model instances without primary key value are unhashable")
|
294
302
|
return hash(self.id)
|
295
303
|
|
296
|
-
def __reduce__(self):
|
304
|
+
def __reduce__(self) -> tuple[Any, tuple[Any, ...], dict[str, Any]]:
|
297
305
|
data = self.__getstate__()
|
298
306
|
data[PLAIN_VERSION_PICKLE_KEY] = plain.runtime.__version__
|
299
307
|
class_id = self._meta.package_label, self._meta.object_name
|
300
308
|
return model_unpickle, (class_id,), data
|
301
309
|
|
302
|
-
def __getstate__(self):
|
310
|
+
def __getstate__(self) -> dict[str, Any]:
|
303
311
|
"""Hook to allow choosing the attributes to pickle."""
|
304
312
|
state = self.__dict__.copy()
|
305
313
|
state["_state"] = copy.copy(state["_state"])
|
@@ -316,7 +324,7 @@ class Model(metaclass=ModelBase):
|
|
316
324
|
state.pop(attr)
|
317
325
|
return state
|
318
326
|
|
319
|
-
def __setstate__(self, state):
|
327
|
+
def __setstate__(self, state: dict[str, Any]) -> None:
|
320
328
|
pickled_version = state.get(PLAIN_VERSION_PICKLE_KEY)
|
321
329
|
if pickled_version:
|
322
330
|
if pickled_version != plain.runtime.__version__:
|
@@ -337,7 +345,7 @@ class Model(metaclass=ModelBase):
|
|
337
345
|
state[attr] = memoryview(value)
|
338
346
|
self.__dict__.update(state)
|
339
347
|
|
340
|
-
def get_deferred_fields(self):
|
348
|
+
def get_deferred_fields(self) -> set[str]:
|
341
349
|
"""
|
342
350
|
Return a set containing names of deferred fields for this instance.
|
343
351
|
"""
|
@@ -347,7 +355,7 @@ class Model(metaclass=ModelBase):
|
|
347
355
|
if f.attname not in self.__dict__
|
348
356
|
}
|
349
357
|
|
350
|
-
def refresh_from_db(self, fields=None):
|
358
|
+
def refresh_from_db(self, fields: list[str] | None = None) -> None:
|
351
359
|
"""
|
352
360
|
Reload field values from the database.
|
353
361
|
|
@@ -368,7 +376,7 @@ class Model(metaclass=ModelBase):
|
|
368
376
|
prefetched_objects_cache = getattr(self, "_prefetched_objects_cache", ())
|
369
377
|
for field in fields:
|
370
378
|
if field in prefetched_objects_cache:
|
371
|
-
del prefetched_objects_cache[field]
|
379
|
+
del prefetched_objects_cache[field] # type: ignore[misc]
|
372
380
|
fields.remove(field)
|
373
381
|
if not fields:
|
374
382
|
return
|
@@ -409,7 +417,7 @@ class Model(metaclass=ModelBase):
|
|
409
417
|
if field.is_cached(self):
|
410
418
|
field.delete_cached_value(self)
|
411
419
|
|
412
|
-
def serializable_value(self, field_name):
|
420
|
+
def serializable_value(self, field_name: str) -> Any:
|
413
421
|
"""
|
414
422
|
Return the value of the field name for this instance. If the field is
|
415
423
|
a foreign key, return the id value instead of the object. If there's
|
@@ -429,11 +437,11 @@ class Model(metaclass=ModelBase):
|
|
429
437
|
def save(
|
430
438
|
self,
|
431
439
|
*,
|
432
|
-
clean_and_validate=True,
|
433
|
-
force_insert=False,
|
434
|
-
force_update=False,
|
435
|
-
update_fields=None,
|
436
|
-
):
|
440
|
+
clean_and_validate: bool = True,
|
441
|
+
force_insert: bool = False,
|
442
|
+
force_update: bool = False,
|
443
|
+
update_fields: Iterable[str] | None = None,
|
444
|
+
) -> None:
|
437
445
|
"""
|
438
446
|
Save the current instance. Override this in a subclass if you want to
|
439
447
|
control the saving process.
|
@@ -490,11 +498,11 @@ class Model(metaclass=ModelBase):
|
|
490
498
|
def save_base(
|
491
499
|
self,
|
492
500
|
*,
|
493
|
-
raw=False,
|
494
|
-
force_insert=False,
|
495
|
-
force_update=False,
|
496
|
-
update_fields=None,
|
497
|
-
):
|
501
|
+
raw: bool = False,
|
502
|
+
force_insert: bool = False,
|
503
|
+
force_update: bool = False,
|
504
|
+
update_fields: Iterable[str] | None = None,
|
505
|
+
) -> None:
|
498
506
|
"""
|
499
507
|
Handle the parts of saving which should be done only once per save,
|
500
508
|
yet need to be done in raw saves, too. This includes some sanity
|
@@ -521,17 +529,17 @@ class Model(metaclass=ModelBase):
|
|
521
529
|
|
522
530
|
def _save_table(
|
523
531
|
self,
|
524
|
-
raw=False,
|
525
|
-
cls=None,
|
526
|
-
force_insert=False,
|
527
|
-
force_update=False,
|
528
|
-
update_fields=None,
|
529
|
-
):
|
532
|
+
raw: bool = False,
|
533
|
+
cls: type[Model] | None = None,
|
534
|
+
force_insert: bool = False,
|
535
|
+
force_update: bool = False,
|
536
|
+
update_fields: Iterable[str] | None = None,
|
537
|
+
) -> bool:
|
530
538
|
"""
|
531
539
|
Do the heavy-lifting involved in saving. Update or insert the data
|
532
540
|
for a single table.
|
533
541
|
"""
|
534
|
-
meta = cls._meta
|
542
|
+
meta = cls._meta # type: ignore[union-attr]
|
535
543
|
non_pks = [f for f in meta.local_concrete_fields if not f.primary_key]
|
536
544
|
|
537
545
|
if update_fields:
|
@@ -591,7 +599,14 @@ class Model(metaclass=ModelBase):
|
|
591
599
|
setattr(self, field.attname, value)
|
592
600
|
return updated
|
593
601
|
|
594
|
-
def _do_update(
|
602
|
+
def _do_update(
|
603
|
+
self,
|
604
|
+
base_qs: QuerySet,
|
605
|
+
id_val: Any,
|
606
|
+
values: list[tuple[Any, Any, Any]],
|
607
|
+
update_fields: Iterable[str] | None,
|
608
|
+
forced_update: bool,
|
609
|
+
) -> bool:
|
595
610
|
"""
|
596
611
|
Try to update the model. Return True if the model was updated (if an
|
597
612
|
update query was done and a matching row was found in the DB).
|
@@ -606,19 +621,27 @@ class Model(metaclass=ModelBase):
|
|
606
621
|
return update_fields is not None or filtered.exists()
|
607
622
|
return filtered._update(values) > 0
|
608
623
|
|
609
|
-
def _do_insert(
|
624
|
+
def _do_insert(
|
625
|
+
self,
|
626
|
+
manager: QuerySet,
|
627
|
+
fields: Sequence[Any],
|
628
|
+
returning_fields: Sequence[Any],
|
629
|
+
raw: bool,
|
630
|
+
) -> list[Any]:
|
610
631
|
"""
|
611
632
|
Do an INSERT. If returning_fields is defined then this method should
|
612
633
|
return the newly created data for the model.
|
613
634
|
"""
|
614
|
-
return manager._insert(
|
635
|
+
return manager._insert( # type: ignore[return-value, arg-type]
|
615
636
|
[self],
|
616
|
-
fields=fields,
|
617
|
-
returning_fields=returning_fields,
|
637
|
+
fields=fields, # type: ignore[arg-type]
|
638
|
+
returning_fields=returning_fields, # type: ignore[arg-type]
|
618
639
|
raw=raw,
|
619
640
|
)
|
620
641
|
|
621
|
-
def _prepare_related_fields_for_save(
|
642
|
+
def _prepare_related_fields_for_save(
|
643
|
+
self, operation_name: str, fields: Sequence[Any] | None = None
|
644
|
+
) -> None:
|
622
645
|
# Ensure that a model instance without a PK hasn't been assigned to
|
623
646
|
# a ForeignKey on this model. If the field is nullable, allowing the save would result in silent data loss.
|
624
647
|
for field in self._meta.concrete_fields:
|
@@ -655,7 +678,7 @@ class Model(metaclass=ModelBase):
|
|
655
678
|
):
|
656
679
|
field.delete_cached_value(self)
|
657
680
|
|
658
|
-
def delete(self):
|
681
|
+
def delete(self) -> tuple[int, dict[str, int]]:
|
659
682
|
if self.id is None:
|
660
683
|
raise ValueError(
|
661
684
|
f"{self._meta.object_name} object can't be deleted because its id attribute is set "
|
@@ -681,7 +704,9 @@ class Model(metaclass=ModelBase):
|
|
681
704
|
choices_dict.get(make_hashable(value), value), strings_only=True
|
682
705
|
)
|
683
706
|
|
684
|
-
def _get_field_value_map(
|
707
|
+
def _get_field_value_map(
|
708
|
+
self, meta: Options | None, exclude: set[str] | None = None
|
709
|
+
) -> dict[str, Value]:
|
685
710
|
if exclude is None:
|
686
711
|
exclude = set()
|
687
712
|
meta = meta or self._meta
|
@@ -691,14 +716,14 @@ class Model(metaclass=ModelBase):
|
|
691
716
|
if field.name not in exclude
|
692
717
|
}
|
693
718
|
|
694
|
-
def prepare_database_save(self, field):
|
719
|
+
def prepare_database_save(self, field: Any) -> Any:
|
695
720
|
if self.id is None:
|
696
721
|
raise ValueError(
|
697
722
|
f"Unsaved model instance {self!r} cannot be used in an ORM query."
|
698
723
|
)
|
699
724
|
return getattr(self, field.remote_field.get_related_field().attname)
|
700
725
|
|
701
|
-
def clean(self):
|
726
|
+
def clean(self) -> None:
|
702
727
|
"""
|
703
728
|
Hook for doing any extra model-wide validation after clean() has been
|
704
729
|
called on every field by self.clean_fields. Any ValidationError raised
|
@@ -707,7 +732,7 @@ class Model(metaclass=ModelBase):
|
|
707
732
|
"""
|
708
733
|
pass
|
709
734
|
|
710
|
-
def validate_unique(self, exclude=None):
|
735
|
+
def validate_unique(self, exclude: set[str] | None = None) -> None:
|
711
736
|
"""
|
712
737
|
Check unique constraints on the model and raise ValidationError if any
|
713
738
|
failed.
|
@@ -717,7 +742,9 @@ class Model(metaclass=ModelBase):
|
|
717
742
|
if errors := self._perform_unique_checks(unique_checks):
|
718
743
|
raise ValidationError(errors)
|
719
744
|
|
720
|
-
def _get_unique_checks(
|
745
|
+
def _get_unique_checks(
|
746
|
+
self, exclude: set[str] | None = None
|
747
|
+
) -> list[tuple[type, tuple[str, ...]]]:
|
721
748
|
"""
|
722
749
|
Return a list of checks to perform. Since validate_unique() could be
|
723
750
|
called from a ModelForm, some fields may have been excluded; we can't
|
@@ -744,7 +771,9 @@ class Model(metaclass=ModelBase):
|
|
744
771
|
|
745
772
|
return unique_checks
|
746
773
|
|
747
|
-
def _perform_unique_checks(
|
774
|
+
def _perform_unique_checks(
|
775
|
+
self, unique_checks: list[tuple[type, tuple[str, ...]]]
|
776
|
+
) -> dict[str, list[ValidationError]]:
|
748
777
|
errors = {}
|
749
778
|
|
750
779
|
for model_class, unique_check in unique_checks:
|
@@ -768,7 +797,7 @@ class Model(metaclass=ModelBase):
|
|
768
797
|
if len(unique_check) != len(lookup_kwargs):
|
769
798
|
continue
|
770
799
|
|
771
|
-
qs = model_class.query.filter(**lookup_kwargs)
|
800
|
+
qs = model_class.query.filter(**lookup_kwargs) # type: ignore[attr-defined]
|
772
801
|
|
773
802
|
# Exclude the current object from the query if we are editing an
|
774
803
|
# instance (as opposed to creating a new one)
|
@@ -788,8 +817,10 @@ class Model(metaclass=ModelBase):
|
|
788
817
|
|
789
818
|
return errors
|
790
819
|
|
791
|
-
def unique_error_message(
|
792
|
-
|
820
|
+
def unique_error_message(
|
821
|
+
self, model_class: type, unique_check: tuple[str, ...]
|
822
|
+
) -> ValidationError:
|
823
|
+
opts = model_class._meta # type: ignore[attr-defined]
|
793
824
|
|
794
825
|
params = {
|
795
826
|
"model": self,
|
@@ -828,11 +859,11 @@ class Model(metaclass=ModelBase):
|
|
828
859
|
params=params,
|
829
860
|
)
|
830
861
|
|
831
|
-
def get_constraints(self):
|
862
|
+
def get_constraints(self) -> list[tuple[type, list[Any]]]:
|
832
863
|
constraints = [(self.__class__, self._meta.constraints)]
|
833
864
|
return constraints
|
834
865
|
|
835
|
-
def validate_constraints(self, exclude=None):
|
866
|
+
def validate_constraints(self, exclude: set[str] | None = None) -> None:
|
836
867
|
constraints = self.get_constraints()
|
837
868
|
|
838
869
|
errors = {}
|
@@ -852,8 +883,12 @@ class Model(metaclass=ModelBase):
|
|
852
883
|
raise ValidationError(errors)
|
853
884
|
|
854
885
|
def full_clean(
|
855
|
-
self,
|
856
|
-
|
886
|
+
self,
|
887
|
+
*,
|
888
|
+
exclude: set[str] | Iterable[str] | None = None,
|
889
|
+
validate_unique: bool = True,
|
890
|
+
validate_constraints: bool = True,
|
891
|
+
) -> None:
|
857
892
|
"""
|
858
893
|
Call clean_fields(), clean(), validate_unique(), and
|
859
894
|
validate_constraints() on the model. Raise a ValidationError for any
|
@@ -900,7 +935,7 @@ class Model(metaclass=ModelBase):
|
|
900
935
|
if errors:
|
901
936
|
raise ValidationError(errors)
|
902
937
|
|
903
|
-
def clean_fields(self, exclude=None):
|
938
|
+
def clean_fields(self, exclude: set[str] | None = None) -> None:
|
904
939
|
"""
|
905
940
|
Clean all fields and raise a ValidationError containing a dict
|
906
941
|
of all validation errors if any occur.
|
@@ -926,7 +961,7 @@ class Model(metaclass=ModelBase):
|
|
926
961
|
raise ValidationError(errors)
|
927
962
|
|
928
963
|
@classmethod
|
929
|
-
def preflight(cls):
|
964
|
+
def preflight(cls) -> list[PreflightResult]:
|
930
965
|
errors = []
|
931
966
|
|
932
967
|
errors += [
|
@@ -956,7 +991,7 @@ class Model(metaclass=ModelBase):
|
|
956
991
|
return errors
|
957
992
|
|
958
993
|
@classmethod
|
959
|
-
def _check_db_table_comment(cls):
|
994
|
+
def _check_db_table_comment(cls) -> list[PreflightResult]:
|
960
995
|
if not cls._meta.db_table_comment:
|
961
996
|
return []
|
962
997
|
errors = []
|
@@ -976,7 +1011,7 @@ class Model(metaclass=ModelBase):
|
|
976
1011
|
return errors
|
977
1012
|
|
978
1013
|
@classmethod
|
979
|
-
def _check_fields(cls):
|
1014
|
+
def _check_fields(cls) -> list[PreflightResult]:
|
980
1015
|
"""Perform all field checks."""
|
981
1016
|
errors = []
|
982
1017
|
for field in cls._meta.local_fields:
|
@@ -986,7 +1021,7 @@ class Model(metaclass=ModelBase):
|
|
986
1021
|
return errors
|
987
1022
|
|
988
1023
|
@classmethod
|
989
|
-
def _check_m2m_through_same_relationship(cls):
|
1024
|
+
def _check_m2m_through_same_relationship(cls) -> list[PreflightResult]:
|
990
1025
|
"""Check if no relationship model is used by more than one m2m field."""
|
991
1026
|
|
992
1027
|
errors = []
|
@@ -1021,7 +1056,7 @@ class Model(metaclass=ModelBase):
|
|
1021
1056
|
return errors
|
1022
1057
|
|
1023
1058
|
@classmethod
|
1024
|
-
def _check_id_field(cls):
|
1059
|
+
def _check_id_field(cls) -> list[PreflightResult]:
|
1025
1060
|
"""Disallow user-defined fields named ``id``."""
|
1026
1061
|
if any(
|
1027
1062
|
f for f in cls._meta.local_fields if f.name == "id" and not f.auto_created
|
@@ -1036,7 +1071,7 @@ class Model(metaclass=ModelBase):
|
|
1036
1071
|
return []
|
1037
1072
|
|
1038
1073
|
@classmethod
|
1039
|
-
def _check_field_name_clashes(cls):
|
1074
|
+
def _check_field_name_clashes(cls) -> list[PreflightResult]:
|
1040
1075
|
"""Forbid field shadowing in multi-table inheritance."""
|
1041
1076
|
errors = []
|
1042
1077
|
used_fields = {} # name or attname -> field
|
@@ -1065,7 +1100,7 @@ class Model(metaclass=ModelBase):
|
|
1065
1100
|
return errors
|
1066
1101
|
|
1067
1102
|
@classmethod
|
1068
|
-
def _check_column_name_clashes(cls):
|
1103
|
+
def _check_column_name_clashes(cls) -> list[PreflightResult]:
|
1069
1104
|
# Store a list of column names which have already been used by other fields.
|
1070
1105
|
used_column_names = []
|
1071
1106
|
errors = []
|
@@ -1089,7 +1124,7 @@ class Model(metaclass=ModelBase):
|
|
1089
1124
|
return errors
|
1090
1125
|
|
1091
1126
|
@classmethod
|
1092
|
-
def _check_model_name_db_lookup_clashes(cls):
|
1127
|
+
def _check_model_name_db_lookup_clashes(cls) -> list[PreflightResult]:
|
1093
1128
|
errors = []
|
1094
1129
|
model_name = cls.__name__
|
1095
1130
|
if model_name.startswith("_") or model_name.endswith("_"):
|
@@ -1113,7 +1148,9 @@ class Model(metaclass=ModelBase):
|
|
1113
1148
|
return errors
|
1114
1149
|
|
1115
1150
|
@classmethod
|
1116
|
-
def _check_property_name_related_field_accessor_clashes(
|
1151
|
+
def _check_property_name_related_field_accessor_clashes(
|
1152
|
+
cls,
|
1153
|
+
) -> list[PreflightResult]:
|
1117
1154
|
errors = []
|
1118
1155
|
property_names = cls._meta._property_names
|
1119
1156
|
related_field_accessors = (
|
@@ -1134,7 +1171,7 @@ class Model(metaclass=ModelBase):
|
|
1134
1171
|
return errors
|
1135
1172
|
|
1136
1173
|
@classmethod
|
1137
|
-
def _check_single_primary_key(cls):
|
1174
|
+
def _check_single_primary_key(cls) -> list[PreflightResult]:
|
1138
1175
|
errors = []
|
1139
1176
|
if sum(1 for f in cls._meta.local_fields if f.primary_key) > 1:
|
1140
1177
|
errors.append(
|
@@ -1148,7 +1185,7 @@ class Model(metaclass=ModelBase):
|
|
1148
1185
|
return errors
|
1149
1186
|
|
1150
1187
|
@classmethod
|
1151
|
-
def _check_indexes(cls):
|
1188
|
+
def _check_indexes(cls) -> list[PreflightResult]:
|
1152
1189
|
"""Check fields, names, and conditions of indexes."""
|
1153
1190
|
errors = []
|
1154
1191
|
references = set()
|
@@ -1229,7 +1266,9 @@ class Model(metaclass=ModelBase):
|
|
1229
1266
|
return errors
|
1230
1267
|
|
1231
1268
|
@classmethod
|
1232
|
-
def _check_local_fields(
|
1269
|
+
def _check_local_fields(
|
1270
|
+
cls, fields: Iterable[str], option: str
|
1271
|
+
) -> list[PreflightResult]:
|
1233
1272
|
from plain import models
|
1234
1273
|
|
1235
1274
|
# In order to avoid hitting the relation tree prematurely, we use our
|
@@ -1274,7 +1313,7 @@ class Model(metaclass=ModelBase):
|
|
1274
1313
|
return errors
|
1275
1314
|
|
1276
1315
|
@classmethod
|
1277
|
-
def _check_ordering(cls):
|
1316
|
+
def _check_ordering(cls) -> list[PreflightResult]:
|
1278
1317
|
"""
|
1279
1318
|
Check "ordering" option -- is it a list of strings and do all fields
|
1280
1319
|
exist?
|
@@ -1365,7 +1404,7 @@ class Model(metaclass=ModelBase):
|
|
1365
1404
|
return errors
|
1366
1405
|
|
1367
1406
|
@classmethod
|
1368
|
-
def _check_long_column_names(cls):
|
1407
|
+
def _check_long_column_names(cls) -> list[PreflightResult]:
|
1369
1408
|
"""
|
1370
1409
|
Check that any auto-generated column names are shorter than the limits
|
1371
1410
|
for each database in which the model will be created.
|
@@ -1428,7 +1467,7 @@ class Model(metaclass=ModelBase):
|
|
1428
1467
|
return errors
|
1429
1468
|
|
1430
1469
|
@classmethod
|
1431
|
-
def _get_expr_references(cls, expr):
|
1470
|
+
def _get_expr_references(cls, expr: Any) -> Iterator[tuple[str, ...]]:
|
1432
1471
|
if isinstance(expr, Q):
|
1433
1472
|
for child in expr.children:
|
1434
1473
|
if isinstance(child, tuple):
|
@@ -1444,7 +1483,7 @@ class Model(metaclass=ModelBase):
|
|
1444
1483
|
yield from cls._get_expr_references(src_expr)
|
1445
1484
|
|
1446
1485
|
@classmethod
|
1447
|
-
def _check_constraints(cls):
|
1486
|
+
def _check_constraints(cls) -> list[PreflightResult]:
|
1448
1487
|
errors = []
|
1449
1488
|
if not (
|
1450
1489
|
db_connection.features.supports_table_check_constraints
|
@@ -1617,7 +1656,7 @@ class Model(metaclass=ModelBase):
|
|
1617
1656
|
########
|
1618
1657
|
|
1619
1658
|
|
1620
|
-
def model_unpickle(model_id):
|
1659
|
+
def model_unpickle(model_id: tuple[str, str] | type[Model]) -> Model:
|
1621
1660
|
"""Used to unpickle Model subclasses with deferred fields."""
|
1622
1661
|
if isinstance(model_id, tuple):
|
1623
1662
|
model = models_registry.get_model(*model_id)
|
@@ -1627,4 +1666,4 @@ def model_unpickle(model_id):
|
|
1627
1666
|
return model.__new__(model)
|
1628
1667
|
|
1629
1668
|
|
1630
|
-
model_unpickle.__safe_for_unpickle__ = True
|
1669
|
+
model_unpickle.__safe_for_unpickle__ = True # type: ignore[attr-defined]
|