plain.models 0.50.0__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 +14 -0
- plain/models/README.md +26 -42
- plain/models/__init__.py +2 -0
- plain/models/backends/base/creation.py +2 -2
- plain/models/backends/base/introspection.py +8 -4
- plain/models/backends/base/schema.py +89 -71
- plain/models/backends/base/validation.py +1 -1
- plain/models/backends/mysql/compiler.py +1 -1
- plain/models/backends/mysql/operations.py +1 -1
- plain/models/backends/mysql/schema.py +4 -4
- plain/models/backends/postgresql/operations.py +1 -1
- plain/models/backends/postgresql/schema.py +3 -3
- plain/models/backends/sqlite3/operations.py +1 -1
- plain/models/backends/sqlite3/schema.py +61 -50
- plain/models/base.py +116 -163
- plain/models/cli.py +4 -4
- plain/models/constraints.py +14 -9
- plain/models/deletion.py +15 -14
- plain/models/expressions.py +1 -1
- plain/models/fields/__init__.py +20 -16
- plain/models/fields/json.py +3 -3
- plain/models/fields/related.py +73 -71
- plain/models/fields/related_descriptors.py +2 -2
- plain/models/fields/related_lookups.py +1 -1
- plain/models/fields/related_managers.py +21 -32
- plain/models/fields/reverse_related.py +8 -8
- plain/models/forms.py +12 -12
- plain/models/indexes.py +5 -4
- plain/models/meta.py +505 -0
- plain/models/migrations/operations/base.py +1 -1
- plain/models/migrations/operations/fields.py +6 -6
- plain/models/migrations/operations/models.py +18 -16
- plain/models/migrations/recorder.py +9 -5
- plain/models/migrations/state.py +35 -46
- plain/models/migrations/utils.py +1 -1
- plain/models/options.py +182 -518
- plain/models/preflight.py +7 -5
- plain/models/query.py +119 -65
- plain/models/query_utils.py +18 -13
- plain/models/registry.py +6 -5
- plain/models/sql/compiler.py +51 -37
- plain/models/sql/query.py +77 -68
- plain/models/sql/subqueries.py +4 -4
- plain/models/utils.py +4 -1
- {plain_models-0.50.0.dist-info → plain_models-0.51.0.dist-info}/METADATA +27 -43
- {plain_models-0.50.0.dist-info → plain_models-0.51.0.dist-info}/RECORD +49 -48
- {plain_models-0.50.0.dist-info → plain_models-0.51.0.dist-info}/WHEEL +0 -0
- {plain_models-0.50.0.dist-info → plain_models-0.51.0.dist-info}/entry_points.txt +0 -0
- {plain_models-0.50.0.dist-info → plain_models-0.51.0.dist-info}/licenses/LICENSE +0 -0
plain/models/sql/compiler.py
CHANGED
@@ -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 (
|
331
|
-
|
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.
|
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,
|
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
|
-
|
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.
|
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
|
-
|
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
|
-
|
1037
|
+
meta,
|
1031
1038
|
transform_function,
|
1032
|
-
) = self._setup_joins(pieces,
|
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
|
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
|
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,
|
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],
|
1079
|
-
) -> tuple[Any, Any, str, list, 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,
|
1089
|
-
pieces,
|
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,
|
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:
|
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
|
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
|
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.
|
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,
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
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(
|
1703
|
-
fields = self.query.fields or [
|
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
|
-
|
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
|
-
|
1806
|
-
|
1819
|
+
options.db_table,
|
1820
|
+
meta.get_field("id").column,
|
1807
1821
|
),
|
1808
1822
|
)
|
1809
1823
|
]
|
1810
|
-
cols = [field.get_col(
|
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.
|
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:
|