plain.models 0.50.0__py3-none-any.whl → 0.51.1__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 (49) hide show
  1. plain/models/CHANGELOG.md +24 -0
  2. plain/models/README.md +26 -42
  3. plain/models/__init__.py +2 -0
  4. plain/models/backends/base/creation.py +2 -2
  5. plain/models/backends/base/introspection.py +8 -4
  6. plain/models/backends/base/schema.py +89 -71
  7. plain/models/backends/base/validation.py +1 -1
  8. plain/models/backends/mysql/compiler.py +1 -1
  9. plain/models/backends/mysql/operations.py +1 -1
  10. plain/models/backends/mysql/schema.py +4 -4
  11. plain/models/backends/postgresql/operations.py +1 -1
  12. plain/models/backends/postgresql/schema.py +3 -3
  13. plain/models/backends/sqlite3/operations.py +1 -1
  14. plain/models/backends/sqlite3/schema.py +61 -50
  15. plain/models/base.py +116 -163
  16. plain/models/cli.py +4 -4
  17. plain/models/constraints.py +14 -9
  18. plain/models/deletion.py +15 -14
  19. plain/models/expressions.py +21 -5
  20. plain/models/fields/__init__.py +20 -16
  21. plain/models/fields/json.py +3 -3
  22. plain/models/fields/related.py +73 -71
  23. plain/models/fields/related_descriptors.py +2 -2
  24. plain/models/fields/related_lookups.py +1 -1
  25. plain/models/fields/related_managers.py +21 -32
  26. plain/models/fields/reverse_related.py +8 -8
  27. plain/models/forms.py +12 -12
  28. plain/models/indexes.py +5 -4
  29. plain/models/meta.py +505 -0
  30. plain/models/migrations/operations/base.py +1 -1
  31. plain/models/migrations/operations/fields.py +6 -6
  32. plain/models/migrations/operations/models.py +18 -16
  33. plain/models/migrations/recorder.py +9 -5
  34. plain/models/migrations/state.py +35 -46
  35. plain/models/migrations/utils.py +1 -1
  36. plain/models/options.py +182 -518
  37. plain/models/preflight.py +7 -5
  38. plain/models/query.py +119 -65
  39. plain/models/query_utils.py +18 -13
  40. plain/models/registry.py +6 -5
  41. plain/models/sql/compiler.py +51 -37
  42. plain/models/sql/query.py +77 -68
  43. plain/models/sql/subqueries.py +4 -4
  44. plain/models/utils.py +4 -1
  45. {plain_models-0.50.0.dist-info → plain_models-0.51.1.dist-info}/METADATA +27 -43
  46. {plain_models-0.50.0.dist-info → plain_models-0.51.1.dist-info}/RECORD +49 -48
  47. {plain_models-0.50.0.dist-info → plain_models-0.51.1.dist-info}/WHEEL +0 -0
  48. {plain_models-0.50.0.dist-info → plain_models-0.51.1.dist-info}/entry_points.txt +0 -0
  49. {plain_models-0.50.0.dist-info → plain_models-0.51.1.dist-info}/licenses/LICENSE +0 -0
@@ -14,6 +14,7 @@ from plain.models.exceptions import EmptyResultSet, FieldError, FullResultSet
14
14
  from plain.models.expressions import F, OrderBy, RawSQL, Ref, Value
15
15
  from plain.models.functions import Cast, Random
16
16
  from plain.models.lookups import Lookup
17
+ from plain.models.meta import Meta
17
18
  from plain.models.query_utils import select_related_descend
18
19
  from plain.models.sql.constants import (
19
20
  CURSOR,
@@ -327,8 +328,12 @@ class SQLCompiler:
327
328
  ordering = self.query.order_by
328
329
  elif self.query.order_by:
329
330
  ordering = self.query.order_by
330
- elif (meta := self.query.get_meta()) and meta.ordering:
331
- ordering = meta.ordering
331
+ elif (
332
+ self.query.model
333
+ and (options := self.query.model.model_options)
334
+ and options.ordering
335
+ ):
336
+ ordering = options.ordering
332
337
  self._meta_ordering = ordering
333
338
  else:
334
339
  ordering = []
@@ -444,7 +449,7 @@ class SQLCompiler:
444
449
  # '-field1__field2__field', etc.
445
450
  yield from self.find_ordering_name(
446
451
  field,
447
- self.query.get_meta(),
452
+ self.query.get_model_meta(),
448
453
  default_order=default_order,
449
454
  )
450
455
 
@@ -947,12 +952,15 @@ class SQLCompiler:
947
952
  self.query.reset_refcounts(refcounts_before)
948
953
 
949
954
  def get_default_columns(
950
- self, select_mask: Any, start_alias: str | None = None, opts: Any = None
955
+ self,
956
+ select_mask: Any,
957
+ start_alias: str | None = None,
958
+ opts: Meta | None = None,
951
959
  ) -> list[Any]:
952
960
  """
953
961
  Compute the default columns for selecting every field in the base
954
962
  model. Will sometimes be called to pull in related models (e.g. via
955
- select_related), in which case "opts" and "start_alias" will be given
963
+ select_related), in which case "opts" (Meta) and "start_alias" will be given
956
964
  to provide a starting point for the traversal.
957
965
 
958
966
  Return a list of strings, quoted appropriately for use in SQL
@@ -962,8 +970,7 @@ class SQLCompiler:
962
970
  """
963
971
  result = []
964
972
  if opts is None:
965
- if (opts := self.query.get_meta()) is None:
966
- return result
973
+ opts = self.query.get_model_meta()
967
974
  start_alias = start_alias or self.query.get_initial_alias()
968
975
 
969
976
  for field in opts.concrete_fields:
@@ -988,7 +995,7 @@ class SQLCompiler:
988
995
  """
989
996
  result = []
990
997
  params = []
991
- opts = self.query.get_meta()
998
+ opts = self.query.get_model_meta()
992
999
 
993
1000
  for name in self.query.distinct_fields:
994
1001
  parts = name.split(LOOKUP_SEP)
@@ -1008,7 +1015,7 @@ class SQLCompiler:
1008
1015
  def find_ordering_name(
1009
1016
  self,
1010
1017
  name: str,
1011
- opts: Any,
1018
+ meta: Meta,
1012
1019
  alias: str | None = None,
1013
1020
  default_order: str = "ASC",
1014
1021
  already_seen: set | None = None,
@@ -1027,9 +1034,9 @@ class SQLCompiler:
1027
1034
  alias,
1028
1035
  joins,
1029
1036
  path,
1030
- opts,
1037
+ meta,
1031
1038
  transform_function,
1032
- ) = self._setup_joins(pieces, opts, alias)
1039
+ ) = self._setup_joins(pieces, meta, alias)
1033
1040
 
1034
1041
  # If we get to this point and the field is a relation to another model,
1035
1042
  # append the default ordering for that model unless it is the
@@ -1037,7 +1044,7 @@ class SQLCompiler:
1037
1044
  # there are transforms to process.
1038
1045
  if (
1039
1046
  field.is_relation
1040
- and opts.ordering
1047
+ and meta.model.model_options.ordering
1041
1048
  and getattr(field, "attname", None) != pieces[-1]
1042
1049
  and not getattr(transform_function, "has_transforms", False)
1043
1050
  ):
@@ -1051,7 +1058,7 @@ class SQLCompiler:
1051
1058
  already_seen.add(join_tuple)
1052
1059
 
1053
1060
  results = []
1054
- for item in opts.ordering:
1061
+ for item in meta.model.model_options.ordering:
1055
1062
  if hasattr(item, "resolve_expression") and not isinstance(
1056
1063
  item, OrderBy
1057
1064
  ):
@@ -1064,7 +1071,7 @@ class SQLCompiler:
1064
1071
  results.extend(
1065
1072
  (expr.prefix_references(f"{name}{LOOKUP_SEP}"), is_ref)
1066
1073
  for expr, is_ref in self.find_ordering_name(
1067
- item, opts, alias, order, already_seen
1074
+ item, meta, alias, order, already_seen
1068
1075
  )
1069
1076
  )
1070
1077
  return results
@@ -1075,8 +1082,8 @@ class SQLCompiler:
1075
1082
  ]
1076
1083
 
1077
1084
  def _setup_joins(
1078
- self, pieces: list[str], opts: Any, alias: str | None
1079
- ) -> tuple[Any, Any, str, list, Any, Any, Any]:
1085
+ self, pieces: list[str], meta: Meta, alias: str | None
1086
+ ) -> tuple[Any, Any, str, list, Any, Meta, Any]:
1080
1087
  """
1081
1088
  Helper method for get_order_by() and get_distinct().
1082
1089
 
@@ -1085,11 +1092,11 @@ class SQLCompiler:
1085
1092
  match. Executing SQL where this is not true is an error.
1086
1093
  """
1087
1094
  alias = alias or self.query.get_initial_alias()
1088
- field, targets, opts, joins, path, transform_function = self.query.setup_joins(
1089
- pieces, opts, alias
1095
+ field, targets, meta, joins, path, transform_function = self.query.setup_joins(
1096
+ pieces, meta, alias
1090
1097
  )
1091
1098
  alias = joins[-1]
1092
- return field, targets, alias, joins, path, opts, transform_function
1099
+ return field, targets, alias, joins, path, meta, transform_function
1093
1100
 
1094
1101
  def get_from_clause(self) -> tuple[list[str], list]:
1095
1102
  """
@@ -1132,7 +1139,7 @@ class SQLCompiler:
1132
1139
  self,
1133
1140
  select: list[Any],
1134
1141
  select_mask: Any,
1135
- opts: Any = None,
1142
+ opts: Meta | None = None,
1136
1143
  root_alias: str | None = None,
1137
1144
  cur_depth: int = 1,
1138
1145
  requested: dict | None = None,
@@ -1143,13 +1150,16 @@ class SQLCompiler:
1143
1150
  depth is measured as the number of connections away from the root model
1144
1151
  (for example, cur_depth=1 means we are looking at models with direct
1145
1152
  connections to the root model).
1153
+
1154
+ Args:
1155
+ opts: Meta for the model being queried (internal metadata)
1146
1156
  """
1147
1157
 
1148
1158
  def _get_field_choices() -> chain:
1149
- direct_choices = (f.name for f in opts.fields if f.is_relation) # type: ignore[attr-defined]
1159
+ direct_choices = (f.name for f in opts.fields if f.is_relation) # type: ignore[union-attr]
1150
1160
  reverse_choices = (
1151
1161
  f.field.related_query_name()
1152
- for f in opts.related_objects # type: ignore[attr-defined]
1162
+ for f in opts.related_objects # type: ignore[union-attr]
1153
1163
  if f.field.primary_key
1154
1164
  )
1155
1165
  return chain(
@@ -1162,7 +1172,7 @@ class SQLCompiler:
1162
1172
  return related_klass_infos
1163
1173
 
1164
1174
  if not opts:
1165
- opts = self.query.get_meta()
1175
+ opts = self.query.get_model_meta()
1166
1176
  root_alias = self.query.get_initial_alias()
1167
1177
 
1168
1178
  # Setup for the case when only particular related fields should be
@@ -1214,7 +1224,9 @@ class SQLCompiler:
1214
1224
  _, _, _, joins, _, _ = self.query.setup_joins([f.name], opts, root_alias)
1215
1225
  alias = joins[-1]
1216
1226
  columns = self.get_default_columns(
1217
- related_select_mask, start_alias=alias, opts=f.remote_field.model._meta
1227
+ related_select_mask,
1228
+ start_alias=alias,
1229
+ opts=f.remote_field.model._model_meta,
1218
1230
  )
1219
1231
  for col in columns:
1220
1232
  select_fields.append(len(select))
@@ -1223,7 +1235,7 @@ class SQLCompiler:
1223
1235
  next_klass_infos = self.get_related_selections(
1224
1236
  select,
1225
1237
  related_select_mask,
1226
- f.remote_field.model._meta,
1238
+ f.remote_field.model._model_meta,
1227
1239
  alias,
1228
1240
  cur_depth + 1,
1229
1241
  next,
@@ -1268,7 +1280,7 @@ class SQLCompiler:
1268
1280
  columns = self.get_default_columns(
1269
1281
  related_select_mask,
1270
1282
  start_alias=alias,
1271
- opts=model._meta,
1283
+ opts=model._model_meta,
1272
1284
  )
1273
1285
  for col in columns:
1274
1286
  select_fields.append(len(select))
@@ -1278,7 +1290,7 @@ class SQLCompiler:
1278
1290
  next_klass_infos = self.get_related_selections(
1279
1291
  select,
1280
1292
  related_select_mask,
1281
- model._meta,
1293
+ model._model_meta,
1282
1294
  alias,
1283
1295
  cur_depth + 1,
1284
1296
  next,
@@ -1325,7 +1337,7 @@ class SQLCompiler:
1325
1337
  columns = self.get_default_columns(
1326
1338
  field_select_mask,
1327
1339
  start_alias=alias,
1328
- opts=model._meta,
1340
+ opts=model._model_meta,
1329
1341
  )
1330
1342
  for col in columns:
1331
1343
  select_fields.append(len(select))
@@ -1335,7 +1347,7 @@ class SQLCompiler:
1335
1347
  next_klass_infos = self.get_related_selections(
1336
1348
  select,
1337
1349
  field_select_mask,
1338
- opts=model._meta,
1350
+ opts=model._model_meta,
1339
1351
  root_alias=alias,
1340
1352
  cur_depth=cur_depth + 1,
1341
1353
  requested=next_requested,
@@ -1695,12 +1707,13 @@ class SQLInsertCompiler(SQLCompiler):
1695
1707
  # We don't need quote_name_unless_alias() here, since these are all
1696
1708
  # going to be column names (so we can avoid the extra overhead).
1697
1709
  qn = self.connection.ops.quote_name
1698
- opts = self.query.get_meta()
1710
+ meta = self.query.get_model_meta()
1711
+ options = self.query.model.model_options
1699
1712
  insert_statement = self.connection.ops.insert_statement(
1700
1713
  on_conflict=self.query.on_conflict,
1701
1714
  )
1702
- result = [f"{insert_statement} {qn(opts.db_table)}"]
1703
- fields = self.query.fields or [opts.get_field("id")]
1715
+ result = [f"{insert_statement} {qn(options.db_table)}"]
1716
+ fields = self.query.fields or [meta.get_field("id")]
1704
1717
  result.append("({})".format(", ".join(qn(f.column) for f in fields)))
1705
1718
 
1706
1719
  if self.query.fields:
@@ -1777,7 +1790,8 @@ class SQLInsertCompiler(SQLCompiler):
1777
1790
  and len(self.query.objs) != 1
1778
1791
  and not self.connection.features.can_return_rows_from_bulk_insert
1779
1792
  )
1780
- opts = self.query.get_meta()
1793
+ meta = self.query.get_model_meta()
1794
+ options = self.query.model.model_options
1781
1795
  self.returning_fields = returning_fields
1782
1796
  with self.connection.cursor() as cursor:
1783
1797
  for sql, params in self.as_sql():
@@ -1802,12 +1816,12 @@ class SQLInsertCompiler(SQLCompiler):
1802
1816
  (
1803
1817
  self.connection.ops.last_insert_id(
1804
1818
  cursor,
1805
- opts.db_table,
1806
- opts.get_field("id").column,
1819
+ options.db_table,
1820
+ meta.get_field("id").column,
1807
1821
  ),
1808
1822
  )
1809
1823
  ]
1810
- cols = [field.get_col(opts.db_table) for field in self.returning_fields]
1824
+ cols = [field.get_col(options.db_table) for field in self.returning_fields]
1811
1825
  converters = self.get_converters(cols)
1812
1826
  if converters:
1813
1827
  rows = list(self.apply_converters(rows, converters))
@@ -1859,7 +1873,7 @@ class SQLDeleteCompiler(SQLCompiler):
1859
1873
  innerq = self.query.clone()
1860
1874
  innerq.__class__ = Query
1861
1875
  innerq.clear_select_clause()
1862
- id_field = self.query.model._meta.get_field("id")
1876
+ id_field = self.query.model._model_meta.get_field("id")
1863
1877
  innerq.select = [id_field.get_col(self.query.get_initial_alias())]
1864
1878
  outerq = Query(self.query.model)
1865
1879
  if not self.connection.features.update_can_self_select: