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.
Files changed (108) hide show
  1. plain/models/CHANGELOG.md +27 -0
  2. plain/models/README.md +26 -42
  3. plain/models/__init__.py +2 -0
  4. plain/models/aggregates.py +42 -19
  5. plain/models/backends/base/base.py +125 -105
  6. plain/models/backends/base/client.py +11 -3
  7. plain/models/backends/base/creation.py +24 -14
  8. plain/models/backends/base/features.py +10 -4
  9. plain/models/backends/base/introspection.py +37 -20
  10. plain/models/backends/base/operations.py +187 -91
  11. plain/models/backends/base/schema.py +338 -218
  12. plain/models/backends/base/validation.py +13 -4
  13. plain/models/backends/ddl_references.py +85 -43
  14. plain/models/backends/mysql/base.py +29 -26
  15. plain/models/backends/mysql/client.py +7 -2
  16. plain/models/backends/mysql/compiler.py +13 -4
  17. plain/models/backends/mysql/creation.py +5 -2
  18. plain/models/backends/mysql/features.py +24 -22
  19. plain/models/backends/mysql/introspection.py +22 -13
  20. plain/models/backends/mysql/operations.py +107 -40
  21. plain/models/backends/mysql/schema.py +52 -28
  22. plain/models/backends/mysql/validation.py +13 -6
  23. plain/models/backends/postgresql/base.py +41 -34
  24. plain/models/backends/postgresql/client.py +7 -2
  25. plain/models/backends/postgresql/creation.py +10 -5
  26. plain/models/backends/postgresql/introspection.py +15 -8
  27. plain/models/backends/postgresql/operations.py +110 -43
  28. plain/models/backends/postgresql/schema.py +88 -49
  29. plain/models/backends/sqlite3/_functions.py +151 -115
  30. plain/models/backends/sqlite3/base.py +37 -23
  31. plain/models/backends/sqlite3/client.py +7 -1
  32. plain/models/backends/sqlite3/creation.py +9 -5
  33. plain/models/backends/sqlite3/features.py +5 -3
  34. plain/models/backends/sqlite3/introspection.py +32 -16
  35. plain/models/backends/sqlite3/operations.py +126 -43
  36. plain/models/backends/sqlite3/schema.py +127 -92
  37. plain/models/backends/utils.py +52 -29
  38. plain/models/backups/cli.py +8 -6
  39. plain/models/backups/clients.py +16 -7
  40. plain/models/backups/core.py +24 -13
  41. plain/models/base.py +221 -229
  42. plain/models/cli.py +98 -67
  43. plain/models/config.py +1 -1
  44. plain/models/connections.py +23 -7
  45. plain/models/constraints.py +79 -56
  46. plain/models/database_url.py +1 -1
  47. plain/models/db.py +6 -2
  48. plain/models/deletion.py +80 -56
  49. plain/models/entrypoints.py +1 -1
  50. plain/models/enums.py +22 -11
  51. plain/models/exceptions.py +23 -8
  52. plain/models/expressions.py +441 -258
  53. plain/models/fields/__init__.py +272 -217
  54. plain/models/fields/json.py +123 -57
  55. plain/models/fields/mixins.py +12 -8
  56. plain/models/fields/related.py +324 -290
  57. plain/models/fields/related_descriptors.py +33 -24
  58. plain/models/fields/related_lookups.py +24 -12
  59. plain/models/fields/related_managers.py +102 -79
  60. plain/models/fields/reverse_related.py +66 -63
  61. plain/models/forms.py +101 -75
  62. plain/models/functions/comparison.py +71 -18
  63. plain/models/functions/datetime.py +79 -29
  64. plain/models/functions/math.py +43 -10
  65. plain/models/functions/mixins.py +24 -7
  66. plain/models/functions/text.py +104 -25
  67. plain/models/functions/window.py +12 -6
  68. plain/models/indexes.py +57 -32
  69. plain/models/lookups.py +228 -153
  70. plain/models/meta.py +505 -0
  71. plain/models/migrations/autodetector.py +86 -43
  72. plain/models/migrations/exceptions.py +7 -3
  73. plain/models/migrations/executor.py +33 -7
  74. plain/models/migrations/graph.py +79 -50
  75. plain/models/migrations/loader.py +45 -22
  76. plain/models/migrations/migration.py +23 -18
  77. plain/models/migrations/operations/base.py +38 -20
  78. plain/models/migrations/operations/fields.py +95 -48
  79. plain/models/migrations/operations/models.py +246 -142
  80. plain/models/migrations/operations/special.py +82 -25
  81. plain/models/migrations/optimizer.py +7 -2
  82. plain/models/migrations/questioner.py +58 -31
  83. plain/models/migrations/recorder.py +27 -16
  84. plain/models/migrations/serializer.py +50 -39
  85. plain/models/migrations/state.py +232 -156
  86. plain/models/migrations/utils.py +30 -14
  87. plain/models/migrations/writer.py +17 -14
  88. plain/models/options.py +189 -518
  89. plain/models/otel.py +16 -6
  90. plain/models/preflight.py +42 -17
  91. plain/models/query.py +400 -251
  92. plain/models/query_utils.py +109 -69
  93. plain/models/registry.py +40 -21
  94. plain/models/sql/compiler.py +190 -127
  95. plain/models/sql/datastructures.py +38 -25
  96. plain/models/sql/query.py +320 -225
  97. plain/models/sql/subqueries.py +36 -25
  98. plain/models/sql/where.py +54 -29
  99. plain/models/test/pytest.py +15 -11
  100. plain/models/test/utils.py +4 -2
  101. plain/models/transaction.py +20 -7
  102. plain/models/utils.py +17 -6
  103. {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/METADATA +27 -43
  104. plain_models-0.51.0.dist-info/RECORD +123 -0
  105. plain_models-0.49.2.dist-info/RECORD +0 -122
  106. {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/WHEEL +0 -0
  107. {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/entry_points.txt +0 -0
  108. {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
- ``_meta.get_fields()`` returns this class to provide access to the field
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._meta.package_label}.{self.related_model._meta.model_name}>"
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
- ``_meta.get_fields()`` returns this class to provide access to the field
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._meta.get_field("id")
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
- ``_meta.get_fields()`` returns this class to provide access to the field
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
- opts = self.through._meta
332
+ meta = self.through._model_meta
330
333
  if self.through_fields:
331
- field = opts.get_field(self.through_fields[0])
334
+ field = meta.get_field(self.through_fields[0])
332
335
  else:
333
- for field in opts.fields:
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