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
@@ -9,7 +9,10 @@ They also act as reverse fields for the purposes of the Meta API because
|
|
9
9
|
they're the closest concept currently available.
|
10
10
|
"""
|
11
11
|
|
12
|
+
from __future__ import annotations
|
13
|
+
|
12
14
|
from functools import cached_property
|
15
|
+
from typing import Any
|
13
16
|
|
14
17
|
from plain.models.exceptions import FieldDoesNotExist, FieldError
|
15
18
|
from plain.utils.hashable import make_hashable
|
@@ -22,7 +25,7 @@ class ForeignObjectRel(FieldCacheMixin):
|
|
22
25
|
"""
|
23
26
|
Used by ForeignKey to store information about the relation.
|
24
27
|
|
25
|
-
``
|
28
|
+
``_model_meta.get_fields()`` returns this class to provide access to the field
|
26
29
|
flags for the reverse relation.
|
27
30
|
"""
|
28
31
|
|
@@ -38,12 +41,12 @@ class ForeignObjectRel(FieldCacheMixin):
|
|
38
41
|
|
39
42
|
def __init__(
|
40
43
|
self,
|
41
|
-
field,
|
42
|
-
to,
|
43
|
-
related_name=None,
|
44
|
-
related_query_name=None,
|
45
|
-
limit_choices_to=None,
|
46
|
-
on_delete=None,
|
44
|
+
field: Any,
|
45
|
+
to: Any,
|
46
|
+
related_name: str | None = None,
|
47
|
+
related_query_name: str | None = None,
|
48
|
+
limit_choices_to: Any = None,
|
49
|
+
on_delete: Any = None,
|
47
50
|
):
|
48
51
|
self.field = field
|
49
52
|
self.model = to
|
@@ -60,19 +63,19 @@ class ForeignObjectRel(FieldCacheMixin):
|
|
60
63
|
# before field.contribute_to_class() has been called will result in
|
61
64
|
# AttributeError
|
62
65
|
@cached_property
|
63
|
-
def hidden(self):
|
66
|
+
def hidden(self) -> bool:
|
64
67
|
return self.is_hidden()
|
65
68
|
|
66
69
|
@cached_property
|
67
|
-
def name(self):
|
70
|
+
def name(self) -> str:
|
68
71
|
return self.field.related_query_name()
|
69
72
|
|
70
73
|
@property
|
71
|
-
def remote_field(self):
|
74
|
+
def remote_field(self) -> Any:
|
72
75
|
return self.field
|
73
76
|
|
74
77
|
@property
|
75
|
-
def target_field(self):
|
78
|
+
def target_field(self) -> Any:
|
76
79
|
"""
|
77
80
|
When filtering against this relation, return the field on the remote
|
78
81
|
model against which the filtering should happen.
|
@@ -83,7 +86,7 @@ class ForeignObjectRel(FieldCacheMixin):
|
|
83
86
|
return target_fields[0]
|
84
87
|
|
85
88
|
@cached_property
|
86
|
-
def related_model(self):
|
89
|
+
def related_model(self) -> Any:
|
87
90
|
if not self.field.model:
|
88
91
|
raise AttributeError(
|
89
92
|
"This property can't be accessed before self.field.contribute_to_class "
|
@@ -92,32 +95,32 @@ class ForeignObjectRel(FieldCacheMixin):
|
|
92
95
|
return self.field.model
|
93
96
|
|
94
97
|
@cached_property
|
95
|
-
def many_to_many(self):
|
98
|
+
def many_to_many(self) -> bool:
|
96
99
|
return self.field.many_to_many
|
97
100
|
|
98
101
|
@cached_property
|
99
|
-
def many_to_one(self):
|
102
|
+
def many_to_one(self) -> bool:
|
100
103
|
return self.field.one_to_many
|
101
104
|
|
102
105
|
@cached_property
|
103
|
-
def one_to_many(self):
|
106
|
+
def one_to_many(self) -> bool:
|
104
107
|
return self.field.many_to_one
|
105
108
|
|
106
|
-
def get_lookup(self, lookup_name):
|
109
|
+
def get_lookup(self, lookup_name: str) -> Any:
|
107
110
|
return self.field.get_lookup(lookup_name)
|
108
111
|
|
109
|
-
def get_internal_type(self):
|
112
|
+
def get_internal_type(self) -> str:
|
110
113
|
return self.field.get_internal_type()
|
111
114
|
|
112
115
|
@property
|
113
|
-
def db_type(self):
|
116
|
+
def db_type(self) -> Any:
|
114
117
|
return self.field.db_type
|
115
118
|
|
116
|
-
def __repr__(self):
|
117
|
-
return f"<{type(self).__name__}: {self.related_model.
|
119
|
+
def __repr__(self) -> str:
|
120
|
+
return f"<{type(self).__name__}: {self.related_model.model_options.package_label}.{self.related_model.model_options.model_name}>"
|
118
121
|
|
119
122
|
@property
|
120
|
-
def identity(self):
|
123
|
+
def identity(self) -> tuple[Any, ...]:
|
121
124
|
return (
|
122
125
|
self.field,
|
123
126
|
self.model,
|
@@ -129,15 +132,15 @@ class ForeignObjectRel(FieldCacheMixin):
|
|
129
132
|
self.multiple,
|
130
133
|
)
|
131
134
|
|
132
|
-
def __eq__(self, other):
|
135
|
+
def __eq__(self, other: object) -> bool:
|
133
136
|
if not isinstance(other, self.__class__):
|
134
137
|
return NotImplemented
|
135
138
|
return self.identity == other.identity
|
136
139
|
|
137
|
-
def __hash__(self):
|
140
|
+
def __hash__(self) -> int:
|
138
141
|
return hash(self.identity)
|
139
142
|
|
140
|
-
def __getstate__(self):
|
143
|
+
def __getstate__(self) -> dict[str, Any]:
|
141
144
|
state = self.__dict__.copy()
|
142
145
|
# Delete the path_infos cached property because it can be recalculated
|
143
146
|
# at first invocation after deserialization. The attribute must be
|
@@ -151,11 +154,11 @@ class ForeignObjectRel(FieldCacheMixin):
|
|
151
154
|
|
152
155
|
def get_choices(
|
153
156
|
self,
|
154
|
-
include_blank=True,
|
155
|
-
blank_choice=BLANK_CHOICE_DASH,
|
156
|
-
limit_choices_to=None,
|
157
|
-
ordering=(),
|
158
|
-
):
|
157
|
+
include_blank: bool = True,
|
158
|
+
blank_choice: list[tuple[str, str]] = BLANK_CHOICE_DASH,
|
159
|
+
limit_choices_to: Any = None,
|
160
|
+
ordering: tuple[str, ...] = (),
|
161
|
+
) -> list[tuple[Any, str]]:
|
159
162
|
"""
|
160
163
|
Return choices with a default blank choices included, for use
|
161
164
|
as <select> choices for this field.
|
@@ -169,17 +172,17 @@ class ForeignObjectRel(FieldCacheMixin):
|
|
169
172
|
qs = qs.order_by(*ordering)
|
170
173
|
return (blank_choice if include_blank else []) + [(x.id, str(x)) for x in qs]
|
171
174
|
|
172
|
-
def is_hidden(self):
|
175
|
+
def is_hidden(self) -> bool:
|
173
176
|
"""Should the related object be hidden?"""
|
174
177
|
return not self.related_name
|
175
178
|
|
176
|
-
def get_joining_columns(self):
|
179
|
+
def get_joining_columns(self) -> Any:
|
177
180
|
return self.field.get_reverse_joining_columns()
|
178
181
|
|
179
|
-
def get_extra_restriction(self, alias, related_alias):
|
182
|
+
def get_extra_restriction(self, alias: str, related_alias: str) -> Any:
|
180
183
|
return self.field.get_extra_restriction(related_alias, alias)
|
181
184
|
|
182
|
-
def set_field_name(self):
|
185
|
+
def set_field_name(self) -> None:
|
183
186
|
"""
|
184
187
|
Set the related field's name, this is not available until later stages
|
185
188
|
of app loading, so set_field_name is called from
|
@@ -189,7 +192,7 @@ class ForeignObjectRel(FieldCacheMixin):
|
|
189
192
|
# example custom multicolumn joins currently have no remote field).
|
190
193
|
self.field_name = None
|
191
194
|
|
192
|
-
def get_accessor_name(self, model=None):
|
195
|
+
def get_accessor_name(self, model: Any = None) -> str | None:
|
193
196
|
# This method encapsulates the logic that decides what name to give an
|
194
197
|
# accessor descriptor that retrieves related many-to-one or
|
195
198
|
# many-to-many objects.
|
@@ -204,17 +207,17 @@ class ForeignObjectRel(FieldCacheMixin):
|
|
204
207
|
return self.related_name
|
205
208
|
return None
|
206
209
|
|
207
|
-
def get_path_info(self, filtered_relation=None):
|
210
|
+
def get_path_info(self, filtered_relation: Any = None) -> Any:
|
208
211
|
if filtered_relation:
|
209
212
|
return self.field.get_reverse_path_info(filtered_relation)
|
210
213
|
else:
|
211
214
|
return self.field.reverse_path_infos
|
212
215
|
|
213
216
|
@cached_property
|
214
|
-
def path_infos(self):
|
217
|
+
def path_infos(self) -> Any:
|
215
218
|
return self.get_path_info()
|
216
219
|
|
217
|
-
def get_cache_name(self):
|
220
|
+
def get_cache_name(self) -> str | None:
|
218
221
|
"""
|
219
222
|
Return the name of the cache key to use for storing an instance of the
|
220
223
|
forward model on the reverse model.
|
@@ -226,7 +229,7 @@ class ManyToOneRel(ForeignObjectRel):
|
|
226
229
|
"""
|
227
230
|
Used by the ForeignKey field to store information about the relation.
|
228
231
|
|
229
|
-
``
|
232
|
+
``_model_meta.get_fields()`` returns this class to provide access to the field
|
230
233
|
flags for the reverse relation.
|
231
234
|
|
232
235
|
Note: Because we somewhat abuse the Rel objects by using them as reverse
|
@@ -239,12 +242,12 @@ class ManyToOneRel(ForeignObjectRel):
|
|
239
242
|
|
240
243
|
def __init__(
|
241
244
|
self,
|
242
|
-
field,
|
243
|
-
to,
|
244
|
-
related_name=None,
|
245
|
-
related_query_name=None,
|
246
|
-
limit_choices_to=None,
|
247
|
-
on_delete=None,
|
245
|
+
field: Any,
|
246
|
+
to: Any,
|
247
|
+
related_name: str | None = None,
|
248
|
+
related_query_name: str | None = None,
|
249
|
+
limit_choices_to: Any = None,
|
250
|
+
on_delete: Any = None,
|
248
251
|
):
|
249
252
|
super().__init__(
|
250
253
|
field,
|
@@ -257,25 +260,25 @@ class ManyToOneRel(ForeignObjectRel):
|
|
257
260
|
|
258
261
|
self.field_name = "id"
|
259
262
|
|
260
|
-
def __getstate__(self):
|
263
|
+
def __getstate__(self) -> dict[str, Any]:
|
261
264
|
state = super().__getstate__()
|
262
265
|
state.pop("related_model", None)
|
263
266
|
return state
|
264
267
|
|
265
268
|
@property
|
266
|
-
def identity(self):
|
269
|
+
def identity(self) -> tuple[Any, ...]:
|
267
270
|
return super().identity + (self.field_name,)
|
268
271
|
|
269
|
-
def get_related_field(self):
|
272
|
+
def get_related_field(self) -> Any:
|
270
273
|
"""
|
271
274
|
Return the Field in the 'to' object to which this relationship is tied.
|
272
275
|
"""
|
273
|
-
field = self.model.
|
276
|
+
field = self.model._model_meta.get_field("id")
|
274
277
|
if not field.concrete:
|
275
278
|
raise FieldDoesNotExist("No related field named 'id'")
|
276
279
|
return field
|
277
280
|
|
278
|
-
def set_field_name(self):
|
281
|
+
def set_field_name(self) -> None:
|
279
282
|
pass
|
280
283
|
|
281
284
|
|
@@ -283,21 +286,21 @@ class ManyToManyRel(ForeignObjectRel):
|
|
283
286
|
"""
|
284
287
|
Used by ManyToManyField to store information about the relation.
|
285
288
|
|
286
|
-
``
|
289
|
+
``_model_meta.get_fields()`` returns this class to provide access to the field
|
287
290
|
flags for the reverse relation.
|
288
291
|
"""
|
289
292
|
|
290
293
|
def __init__(
|
291
294
|
self,
|
292
|
-
field,
|
293
|
-
to,
|
295
|
+
field: Any,
|
296
|
+
to: Any,
|
294
297
|
*,
|
295
|
-
through,
|
296
|
-
through_fields=None,
|
297
|
-
related_name=None,
|
298
|
-
related_query_name=None,
|
299
|
-
limit_choices_to=None,
|
300
|
-
symmetrical=True,
|
298
|
+
through: Any,
|
299
|
+
through_fields: tuple[str, str] | None = None,
|
300
|
+
related_name: str | None = None,
|
301
|
+
related_query_name: str | None = None,
|
302
|
+
limit_choices_to: Any = None,
|
303
|
+
symmetrical: bool = True,
|
301
304
|
):
|
302
305
|
super().__init__(
|
303
306
|
field,
|
@@ -314,23 +317,23 @@ class ManyToManyRel(ForeignObjectRel):
|
|
314
317
|
self.db_constraint = True
|
315
318
|
|
316
319
|
@property
|
317
|
-
def identity(self):
|
320
|
+
def identity(self) -> tuple[Any, ...]:
|
318
321
|
return super().identity + (
|
319
322
|
self.through,
|
320
323
|
make_hashable(self.through_fields),
|
321
324
|
self.db_constraint,
|
322
325
|
)
|
323
326
|
|
324
|
-
def get_related_field(self):
|
327
|
+
def get_related_field(self) -> Any:
|
325
328
|
"""
|
326
329
|
Return the field in the 'to' object to which this relationship is tied.
|
327
330
|
Provided for symmetry with ManyToOneRel.
|
328
331
|
"""
|
329
|
-
|
332
|
+
meta = self.through._model_meta
|
330
333
|
if self.through_fields:
|
331
|
-
field =
|
334
|
+
field = meta.get_field(self.through_fields[0])
|
332
335
|
else:
|
333
|
-
for field in
|
336
|
+
for field in meta.fields:
|
334
337
|
rel = getattr(field, "remote_field", None)
|
335
338
|
if rel and rel.model == self.model:
|
336
339
|
break
|