plain.models 0.47.0__py3-none-any.whl → 0.49.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/__init__.py +0 -3
- plain/models/aggregates.py +1 -1
- plain/models/backends/base/creation.py +1 -0
- plain/models/backends/mysql/compiler.py +1 -1
- plain/models/backends/sqlite3/operations.py +1 -1
- plain/models/base.py +34 -94
- plain/models/cli.py +66 -0
- plain/models/constraints.py +2 -1
- plain/models/deletion.py +3 -5
- plain/models/exceptions.py +108 -0
- plain/models/expressions.py +1 -1
- plain/models/fields/__init__.py +3 -41
- plain/models/fields/related.py +15 -22
- plain/models/fields/related_descriptors.py +1 -3
- plain/models/fields/related_managers.py +1 -1
- plain/models/fields/reverse_related.py +3 -5
- plain/models/forms.py +1 -1
- plain/models/lookups.py +1 -1
- plain/models/migrations/executor.py +29 -27
- plain/models/migrations/state.py +1 -1
- plain/models/options.py +4 -16
- plain/models/query.py +12 -10
- plain/models/query_utils.py +2 -2
- plain/models/sql/compiler.py +6 -6
- plain/models/sql/datastructures.py +1 -1
- plain/models/sql/query.py +4 -4
- plain/models/sql/subqueries.py +3 -3
- plain/models/sql/where.py +1 -1
- {plain_models-0.47.0.dist-info → plain_models-0.49.0.dist-info}/METADATA +1 -1
- {plain_models-0.47.0.dist-info → plain_models-0.49.0.dist-info}/RECORD +34 -34
- {plain_models-0.47.0.dist-info → plain_models-0.49.0.dist-info}/WHEEL +0 -0
- {plain_models-0.47.0.dist-info → plain_models-0.49.0.dist-info}/entry_points.txt +0 -0
- {plain_models-0.47.0.dist-info → plain_models-0.49.0.dist-info}/licenses/LICENSE +0 -0
plain/models/fields/related.py
CHANGED
@@ -3,6 +3,7 @@ from functools import cached_property, partial
|
|
3
3
|
from plain import exceptions
|
4
4
|
from plain.models.constants import LOOKUP_SEP
|
5
5
|
from plain.models.deletion import SET_DEFAULT, SET_NULL
|
6
|
+
from plain.models.exceptions import FieldDoesNotExist, FieldError
|
6
7
|
from plain.models.query_utils import PathInfo, Q
|
7
8
|
from plain.models.utils import make_model_tuple
|
8
9
|
from plain.preflight import PreflightResult
|
@@ -303,8 +304,8 @@ class RelatedField(FieldCacheMixin, Field):
|
|
303
304
|
# columns from another table.
|
304
305
|
return None
|
305
306
|
|
306
|
-
def contribute_to_class(self, cls, name
|
307
|
-
super().contribute_to_class(cls, name
|
307
|
+
def contribute_to_class(self, cls, name):
|
308
|
+
super().contribute_to_class(cls, name)
|
308
309
|
|
309
310
|
self.opts = cls._meta
|
310
311
|
|
@@ -407,7 +408,7 @@ class RelatedField(FieldCacheMixin, Field):
|
|
407
408
|
"""
|
408
409
|
target_fields = self.path_infos[-1].target_fields
|
409
410
|
if len(target_fields) > 1:
|
410
|
-
raise
|
411
|
+
raise FieldError(
|
411
412
|
"The relation has multiple target fields, but only single target field "
|
412
413
|
"was asked for"
|
413
414
|
)
|
@@ -582,15 +583,15 @@ class ForeignKey(RelatedField):
|
|
582
583
|
def reverse_path_infos(self):
|
583
584
|
return self.get_reverse_path_info()
|
584
585
|
|
585
|
-
def contribute_to_class(self, cls, name
|
586
|
-
super().contribute_to_class(cls, name
|
586
|
+
def contribute_to_class(self, cls, name):
|
587
|
+
super().contribute_to_class(cls, name)
|
587
588
|
setattr(cls, self.name, self.forward_related_accessor_class(self))
|
588
589
|
|
589
590
|
def contribute_to_related_class(self, cls, related):
|
590
591
|
# Internal FK's - i.e., those with a related name ending with '+'
|
591
592
|
if not self.remote_field.is_hidden():
|
592
593
|
setattr(
|
593
|
-
cls
|
594
|
+
cls,
|
594
595
|
related.get_accessor_name(),
|
595
596
|
self.related_accessor_class(related),
|
596
597
|
)
|
@@ -696,13 +697,10 @@ class ForeignKey(RelatedField):
|
|
696
697
|
related_fields = [(from_field, to_field)]
|
697
698
|
|
698
699
|
for from_field, to_field in related_fields:
|
699
|
-
if
|
700
|
-
|
701
|
-
and to_field.model != self.remote_field.model._meta.concrete_model
|
702
|
-
):
|
703
|
-
raise exceptions.FieldError(
|
700
|
+
if to_field and to_field.model != self.remote_field.model:
|
701
|
+
raise FieldError(
|
704
702
|
f"'{self.model._meta.label}.{self.name}' refers to field '{to_field.name}' which is not local to model "
|
705
|
-
f"'{self.remote_field.model._meta.
|
703
|
+
f"'{self.remote_field.model._meta.label}'."
|
706
704
|
)
|
707
705
|
return related_fields
|
708
706
|
|
@@ -1075,7 +1073,7 @@ class ManyToManyField(RelatedField):
|
|
1075
1073
|
|
1076
1074
|
try:
|
1077
1075
|
field = through._meta.get_field(field_name)
|
1078
|
-
except
|
1076
|
+
except FieldDoesNotExist:
|
1079
1077
|
errors.append(
|
1080
1078
|
PreflightResult(
|
1081
1079
|
fix=f"The intermediary model '{qualified_model_name}' has no field '{field_name}'. {fix}",
|
@@ -1109,13 +1107,8 @@ class ManyToManyField(RelatedField):
|
|
1109
1107
|
}
|
1110
1108
|
m2m_db_table = self.m2m_db_table()
|
1111
1109
|
model = registered_tables.get(m2m_db_table)
|
1112
|
-
#
|
1113
|
-
|
1114
|
-
if (
|
1115
|
-
model
|
1116
|
-
and model._meta.concrete_model
|
1117
|
-
!= self.remote_field.through._meta.concrete_model
|
1118
|
-
):
|
1110
|
+
# Check if there's already a m2m field using the same through model.
|
1111
|
+
if model and model != self.remote_field.through:
|
1119
1112
|
clashing_obj = model._meta.label
|
1120
1113
|
return [
|
1121
1114
|
PreflightResult(
|
@@ -1245,8 +1238,8 @@ class ManyToManyField(RelatedField):
|
|
1245
1238
|
break
|
1246
1239
|
return getattr(self, cache_attr)
|
1247
1240
|
|
1248
|
-
def contribute_to_class(self, cls, name
|
1249
|
-
super().contribute_to_class(cls, name
|
1241
|
+
def contribute_to_class(self, cls, name):
|
1242
|
+
super().contribute_to_class(cls, name)
|
1250
1243
|
|
1251
1244
|
def resolve_through_model(_, model, field):
|
1252
1245
|
field.remote_field.through = model
|
@@ -208,9 +208,7 @@ class ForwardManyToOneDescriptor:
|
|
208
208
|
value = value if value else None
|
209
209
|
|
210
210
|
# An object must be an instance of the related class.
|
211
|
-
if value is not None and not isinstance(
|
212
|
-
value, self.field.remote_field.model._meta.concrete_model
|
213
|
-
):
|
211
|
+
if value is not None and not isinstance(value, self.field.remote_field.model):
|
214
212
|
raise ValueError(
|
215
213
|
f'Cannot assign "{value!r}": "{instance._meta.object_name}.{self.field.name}" must be a "{self.field.remote_field.model._meta.object_name}" instance.'
|
216
214
|
)
|
@@ -80,7 +80,7 @@ class ReverseManyToOneManager(BaseRelatedManager):
|
|
80
80
|
"""
|
81
81
|
Filter the queryset for the instance this manager is bound to.
|
82
82
|
"""
|
83
|
-
from plain.exceptions import FieldError
|
83
|
+
from plain.models.exceptions import FieldError
|
84
84
|
|
85
85
|
queryset._defer_next_filter = True
|
86
86
|
queryset = queryset.filter(**self.core_filters)
|
@@ -11,7 +11,7 @@ they're the closest concept currently available.
|
|
11
11
|
|
12
12
|
from functools import cached_property
|
13
13
|
|
14
|
-
from plain import
|
14
|
+
from plain.models.exceptions import FieldDoesNotExist, FieldError
|
15
15
|
from plain.utils.hashable import make_hashable
|
16
16
|
|
17
17
|
from . import BLANK_CHOICE_DASH
|
@@ -79,9 +79,7 @@ class ForeignObjectRel(FieldCacheMixin):
|
|
79
79
|
"""
|
80
80
|
target_fields = self.path_infos[-1].target_fields
|
81
81
|
if len(target_fields) > 1:
|
82
|
-
raise
|
83
|
-
"Can't use target_field for multicolumn relations."
|
84
|
-
)
|
82
|
+
raise FieldError("Can't use target_field for multicolumn relations.")
|
85
83
|
return target_fields[0]
|
86
84
|
|
87
85
|
@cached_property
|
@@ -274,7 +272,7 @@ class ManyToOneRel(ForeignObjectRel):
|
|
274
272
|
"""
|
275
273
|
field = self.model._meta.get_field("id")
|
276
274
|
if not field.concrete:
|
277
|
-
raise
|
275
|
+
raise FieldDoesNotExist("No related field named 'id'")
|
278
276
|
return field
|
279
277
|
|
280
278
|
def set_field_name(self):
|
plain/models/forms.py
CHANGED
@@ -7,13 +7,13 @@ from itertools import chain
|
|
7
7
|
|
8
8
|
from plain.exceptions import (
|
9
9
|
NON_FIELD_ERRORS,
|
10
|
-
FieldError,
|
11
10
|
ImproperlyConfigured,
|
12
11
|
ValidationError,
|
13
12
|
)
|
14
13
|
from plain.forms import fields
|
15
14
|
from plain.forms.fields import ChoiceField, Field
|
16
15
|
from plain.forms.forms import BaseForm, DeclarativeFieldsMetaclass
|
16
|
+
from plain.models.exceptions import FieldError
|
17
17
|
|
18
18
|
__all__ = (
|
19
19
|
"ModelForm",
|
plain/models/lookups.py
CHANGED
@@ -2,7 +2,7 @@ import itertools
|
|
2
2
|
import math
|
3
3
|
from functools import cached_property
|
4
4
|
|
5
|
-
from plain.exceptions import EmptyResultSet, FullResultSet
|
5
|
+
from plain.models.exceptions import EmptyResultSet, FullResultSet
|
6
6
|
from plain.models.expressions import Expression, Func, Value
|
7
7
|
from plain.models.fields import (
|
8
8
|
BooleanField,
|
@@ -1,3 +1,6 @@
|
|
1
|
+
from contextlib import nullcontext
|
2
|
+
|
3
|
+
from ..transaction import atomic
|
1
4
|
from .loader import MigrationLoader
|
2
5
|
from .recorder import MigrationRecorder
|
3
6
|
from .state import ProjectState
|
@@ -52,12 +55,14 @@ class MigrationExecutor:
|
|
52
55
|
migration.mutate_state(state, preserve=False)
|
53
56
|
return state
|
54
57
|
|
55
|
-
def migrate(self, targets, plan=None, state=None, fake=False):
|
58
|
+
def migrate(self, targets, plan=None, state=None, fake=False, atomic_batch=False):
|
56
59
|
"""
|
57
60
|
Migrate the database up to the given targets.
|
58
61
|
|
59
62
|
Plain first needs to create all project states before a migration is
|
60
63
|
(un)applied and in a second step run all the database operations.
|
64
|
+
|
65
|
+
atomic_batch: Whether to run all migrations in a single transaction.
|
61
66
|
"""
|
62
67
|
# The plain_migrations table must be present to record applied
|
63
68
|
# migrations, but don't create it if there are no migrations to apply.
|
@@ -82,34 +87,31 @@ class MigrationExecutor:
|
|
82
87
|
if state is None:
|
83
88
|
# The resulting state should still include applied migrations.
|
84
89
|
state = self._create_project_state(with_applied_migrations=True)
|
85
|
-
state = self._migrate_all_forwards(state, plan, full_plan, fake=fake)
|
86
|
-
|
87
|
-
self.check_replacements()
|
88
90
|
|
89
|
-
|
91
|
+
migrations_to_run = set(plan)
|
92
|
+
|
93
|
+
# Choose context manager based on atomic_batch
|
94
|
+
batch_context = atomic if (atomic_batch and len(plan) > 1) else nullcontext
|
95
|
+
|
96
|
+
with batch_context():
|
97
|
+
for migration in full_plan:
|
98
|
+
if not migrations_to_run:
|
99
|
+
# We remove every migration that we applied from these sets so
|
100
|
+
# that we can bail out once the last migration has been applied
|
101
|
+
# and don't always run until the very end of the migration
|
102
|
+
# process.
|
103
|
+
break
|
104
|
+
if migration in migrations_to_run:
|
105
|
+
if "models_registry" not in state.__dict__:
|
106
|
+
if self.progress_callback:
|
107
|
+
self.progress_callback("render_start")
|
108
|
+
state.models_registry # Render all -- performance critical
|
109
|
+
if self.progress_callback:
|
110
|
+
self.progress_callback("render_success")
|
111
|
+
state = self.apply_migration(state, migration, fake=fake)
|
112
|
+
migrations_to_run.remove(migration)
|
90
113
|
|
91
|
-
|
92
|
-
"""
|
93
|
-
Take a list of 2-tuples of the form (migration instance, False) and
|
94
|
-
apply them in the order they occur in the full_plan.
|
95
|
-
"""
|
96
|
-
migrations_to_run = set(plan)
|
97
|
-
for migration in full_plan:
|
98
|
-
if not migrations_to_run:
|
99
|
-
# We remove every migration that we applied from these sets so
|
100
|
-
# that we can bail out once the last migration has been applied
|
101
|
-
# and don't always run until the very end of the migration
|
102
|
-
# process.
|
103
|
-
break
|
104
|
-
if migration in migrations_to_run:
|
105
|
-
if "models_registry" not in state.__dict__:
|
106
|
-
if self.progress_callback:
|
107
|
-
self.progress_callback("render_start")
|
108
|
-
state.models_registry # Render all -- performance critical
|
109
|
-
if self.progress_callback:
|
110
|
-
self.progress_callback("render_success")
|
111
|
-
state = self.apply_migration(state, migration, fake=fake)
|
112
|
-
migrations_to_run.remove(migration)
|
114
|
+
self.check_replacements()
|
113
115
|
|
114
116
|
return state
|
115
117
|
|
plain/models/migrations/state.py
CHANGED
@@ -4,7 +4,7 @@ from contextlib import contextmanager
|
|
4
4
|
from functools import cached_property, partial
|
5
5
|
|
6
6
|
from plain import models
|
7
|
-
from plain.exceptions import FieldDoesNotExist
|
7
|
+
from plain.models.exceptions import FieldDoesNotExist
|
8
8
|
from plain.models.fields import NOT_PROVIDED
|
9
9
|
from plain.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT
|
10
10
|
from plain.models.migrations.utils import field_is_referenced, get_references
|
plain/models/options.py
CHANGED
@@ -3,11 +3,10 @@ import inspect
|
|
3
3
|
from collections import defaultdict
|
4
4
|
from functools import cached_property
|
5
5
|
|
6
|
-
from plain.exceptions import FieldDoesNotExist
|
7
6
|
from plain.models import models_registry
|
8
7
|
from plain.models.constraints import UniqueConstraint
|
9
8
|
from plain.models.db import db_connection
|
10
|
-
from plain.models.
|
9
|
+
from plain.models.exceptions import FieldDoesNotExist
|
11
10
|
from plain.models.query import QuerySet
|
12
11
|
from plain.utils.datastructures import ImmutableList
|
13
12
|
|
@@ -70,11 +69,6 @@ class Options:
|
|
70
69
|
self.required_db_vendor = None
|
71
70
|
self.meta = meta
|
72
71
|
|
73
|
-
# For any non-abstract class, the concrete class is the model
|
74
|
-
# in the end of the proxy_for_model chain. In particular, for
|
75
|
-
# concrete models, the concrete_model is always the class itself.
|
76
|
-
self.concrete_model = None
|
77
|
-
|
78
72
|
# List of all lookups defined in ForeignKey 'limit_choices_to' options
|
79
73
|
# from *other* models. Needed for some admin checks. Internal use only.
|
80
74
|
self.related_fkey_lookups = []
|
@@ -156,11 +150,7 @@ class Options:
|
|
156
150
|
new_objs.append(obj)
|
157
151
|
return new_objs
|
158
152
|
|
159
|
-
def
|
160
|
-
if not any(f.name == "id" for f in self.local_fields):
|
161
|
-
model.add_to_class("id", PrimaryKeyField())
|
162
|
-
|
163
|
-
def add_field(self, field, private=False):
|
153
|
+
def add_field(self, field):
|
164
154
|
# Insert the given field in the order in which it was created, using
|
165
155
|
# the "creation_counter" attribute of the field.
|
166
156
|
# Move many-to-many related fields from self.fields into
|
@@ -417,7 +407,7 @@ class Options:
|
|
417
407
|
)
|
418
408
|
for f in fields_with_relations:
|
419
409
|
if not isinstance(f.remote_field.model, str):
|
420
|
-
remote_label = f.remote_field.model._meta.
|
410
|
+
remote_label = f.remote_field.model._meta.label
|
421
411
|
related_objects_graph[remote_label].append(f)
|
422
412
|
|
423
413
|
for model in all_models:
|
@@ -426,9 +416,7 @@ class Options:
|
|
426
416
|
# __dict__ takes precedence over a data descriptor (such as
|
427
417
|
# @cached_property). This means that the _meta._relation_tree is
|
428
418
|
# only called if related_objects is not in __dict__.
|
429
|
-
related_objects = related_objects_graph[
|
430
|
-
model._meta.concrete_model._meta.label
|
431
|
-
]
|
419
|
+
related_objects = related_objects_graph[model._meta.label]
|
432
420
|
model._meta.__dict__["_relation_tree"] = related_objects
|
433
421
|
# It seems it is possible that self is not in all_models, so guard
|
434
422
|
# against that with default for get().
|
plain/models/query.py
CHANGED
@@ -9,7 +9,6 @@ from functools import cached_property
|
|
9
9
|
from itertools import chain, islice
|
10
10
|
|
11
11
|
import plain.runtime
|
12
|
-
from plain import exceptions
|
13
12
|
from plain.exceptions import ValidationError
|
14
13
|
from plain.models import (
|
15
14
|
sql,
|
@@ -22,6 +21,11 @@ from plain.models.db import (
|
|
22
21
|
NotSupportedError,
|
23
22
|
db_connection,
|
24
23
|
)
|
24
|
+
from plain.models.exceptions import (
|
25
|
+
FieldDoesNotExist,
|
26
|
+
FieldError,
|
27
|
+
ObjectDoesNotExist,
|
28
|
+
)
|
25
29
|
from plain.models.expressions import Case, F, Value, When
|
26
30
|
from plain.models.fields import (
|
27
31
|
DateField,
|
@@ -129,9 +133,7 @@ class RawModelIterable(BaseIterable):
|
|
129
133
|
) = self.queryset.resolve_model_init_order()
|
130
134
|
model_cls = self.queryset.model
|
131
135
|
if "id" not in model_init_names:
|
132
|
-
raise
|
133
|
-
"Raw query must include the primary key"
|
134
|
-
)
|
136
|
+
raise FieldDoesNotExist("Raw query must include the primary key")
|
135
137
|
fields = [self.queryset.model_fields.get(c) for c in self.queryset.columns]
|
136
138
|
converters = compiler.get_converters(
|
137
139
|
[f.get_col(f.model._meta.db_table) if f else None for f in fields]
|
@@ -850,12 +852,12 @@ class QuerySet:
|
|
850
852
|
for param in params:
|
851
853
|
try:
|
852
854
|
self.model._meta.get_field(param)
|
853
|
-
except
|
855
|
+
except FieldDoesNotExist:
|
854
856
|
# It's okay to use a model's property if it has a setter.
|
855
857
|
if not (param in property_names and getattr(self.model, param).fset):
|
856
858
|
invalid_params.append(param)
|
857
859
|
if invalid_params:
|
858
|
-
raise
|
860
|
+
raise FieldError(
|
859
861
|
"Invalid field name(s) for model {}: '{}'.".format(
|
860
862
|
self.model._meta.object_name,
|
861
863
|
"', '".join(sorted(invalid_params)),
|
@@ -982,7 +984,7 @@ class QuerySet:
|
|
982
984
|
descending = True
|
983
985
|
if annotation := query.annotations.get(alias):
|
984
986
|
if getattr(annotation, "contains_aggregate", False):
|
985
|
-
raise
|
987
|
+
raise FieldError(
|
986
988
|
f"Cannot update when ordering by an aggregate: {annotation}"
|
987
989
|
)
|
988
990
|
if descending:
|
@@ -1034,7 +1036,7 @@ class QuerySet:
|
|
1034
1036
|
"Cannot call QuerySet.contains() after .values() or .values_list()."
|
1035
1037
|
)
|
1036
1038
|
try:
|
1037
|
-
if obj.
|
1039
|
+
if obj.__class__ != self.model:
|
1038
1040
|
return False
|
1039
1041
|
except AttributeError:
|
1040
1042
|
raise TypeError("'obj' must be a model instance.")
|
@@ -2039,7 +2041,7 @@ def prefetch_related_objects(model_instances, *related_lookups):
|
|
2039
2041
|
else:
|
2040
2042
|
try:
|
2041
2043
|
new_obj = getattr(obj, through_attr)
|
2042
|
-
except
|
2044
|
+
except ObjectDoesNotExist:
|
2043
2045
|
continue
|
2044
2046
|
if new_obj is None:
|
2045
2047
|
continue
|
@@ -2174,7 +2176,7 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
|
|
2174
2176
|
model = instances[0].__class__
|
2175
2177
|
try:
|
2176
2178
|
model._meta.get_field(to_attr)
|
2177
|
-
except
|
2179
|
+
except FieldDoesNotExist:
|
2178
2180
|
pass
|
2179
2181
|
else:
|
2180
2182
|
msg = "to_attr={} conflicts with a field on the {} model."
|
plain/models/query_utils.py
CHANGED
@@ -11,9 +11,9 @@ import inspect
|
|
11
11
|
import logging
|
12
12
|
from collections import namedtuple
|
13
13
|
|
14
|
-
from plain.exceptions import FieldError
|
15
14
|
from plain.models.constants import LOOKUP_SEP
|
16
15
|
from plain.models.db import DatabaseError, db_connection
|
16
|
+
from plain.models.exceptions import FieldError
|
17
17
|
from plain.utils import tree
|
18
18
|
|
19
19
|
logger = logging.getLogger("plain.models")
|
@@ -355,7 +355,7 @@ def check_rel_lookup_compatibility(model, target_opts, field):
|
|
355
355
|
"""
|
356
356
|
|
357
357
|
def check(opts):
|
358
|
-
return model
|
358
|
+
return model == opts.model
|
359
359
|
|
360
360
|
# If the field is a primary key, then doing a query against the field's
|
361
361
|
# model is ok, too. Consider the case:
|
plain/models/sql/compiler.py
CHANGED
@@ -4,9 +4,9 @@ import re
|
|
4
4
|
from functools import cached_property, partial
|
5
5
|
from itertools import chain
|
6
6
|
|
7
|
-
from plain.exceptions import EmptyResultSet, FieldError, FullResultSet
|
8
7
|
from plain.models.constants import LOOKUP_SEP
|
9
8
|
from plain.models.db import DatabaseError, NotSupportedError
|
9
|
+
from plain.models.exceptions import EmptyResultSet, FieldError, FullResultSet
|
10
10
|
from plain.models.expressions import F, OrderBy, RawSQL, Ref, Value
|
11
11
|
from plain.models.functions import Cast, Random
|
12
12
|
from plain.models.lookups import Lookup
|
@@ -940,9 +940,9 @@ class SQLCompiler:
|
|
940
940
|
start_alias = start_alias or self.query.get_initial_alias()
|
941
941
|
|
942
942
|
for field in opts.concrete_fields:
|
943
|
-
model = field.model
|
944
|
-
#
|
945
|
-
#
|
943
|
+
model = field.model
|
944
|
+
# Since we no longer have proxy models or inheritance,
|
945
|
+
# the field's model should always be the same as opts.model.
|
946
946
|
if model == opts.model:
|
947
947
|
model = None
|
948
948
|
if select_mask and field not in select_mask:
|
@@ -1331,9 +1331,9 @@ class SQLCompiler:
|
|
1331
1331
|
select_fields is filled recursively, so it also contains fields
|
1332
1332
|
from the parent models.
|
1333
1333
|
"""
|
1334
|
-
|
1334
|
+
model = klass_info["model"]
|
1335
1335
|
for select_index in klass_info["select_fields"]:
|
1336
|
-
if self.select[select_index][0].target.model ==
|
1336
|
+
if self.select[select_index][0].target.model == model:
|
1337
1337
|
return self.select[select_index][0]
|
1338
1338
|
|
1339
1339
|
def _get_field_choices():
|
plain/models/sql/query.py
CHANGED
@@ -17,10 +17,10 @@ from functools import cached_property
|
|
17
17
|
from itertools import chain, count, product
|
18
18
|
from string import ascii_uppercase
|
19
19
|
|
20
|
-
from plain.exceptions import FieldDoesNotExist, FieldError
|
21
20
|
from plain.models.aggregates import Count
|
22
21
|
from plain.models.constants import LOOKUP_SEP
|
23
22
|
from plain.models.db import NotSupportedError, db_connection
|
23
|
+
from plain.models.exceptions import FieldDoesNotExist, FieldError
|
24
24
|
from plain.models.expressions import (
|
25
25
|
BaseExpression,
|
26
26
|
Col,
|
@@ -706,7 +706,7 @@ class Query(BaseExpression):
|
|
706
706
|
if not field.is_relation:
|
707
707
|
raise FieldError(next(iter(field_mask)))
|
708
708
|
field_select_mask = select_mask.setdefault(field, {})
|
709
|
-
related_model = field.remote_field.model
|
709
|
+
related_model = field.remote_field.model
|
710
710
|
self._get_defer_select_mask(
|
711
711
|
related_model._meta, field_mask, field_select_mask
|
712
712
|
)
|
@@ -721,7 +721,7 @@ class Query(BaseExpression):
|
|
721
721
|
else:
|
722
722
|
field = opts.get_field(field_name).field
|
723
723
|
field_select_mask = select_mask.setdefault(field, {})
|
724
|
-
related_model = field.model
|
724
|
+
related_model = field.model
|
725
725
|
self._get_defer_select_mask(
|
726
726
|
related_model._meta, field_mask, field_select_mask
|
727
727
|
)
|
@@ -738,7 +738,7 @@ class Query(BaseExpression):
|
|
738
738
|
if field_mask:
|
739
739
|
if not field.is_relation:
|
740
740
|
raise FieldError(next(iter(field_mask)))
|
741
|
-
related_model = field.remote_field.model
|
741
|
+
related_model = field.remote_field.model
|
742
742
|
self._get_only_select_mask(
|
743
743
|
related_model._meta, field_mask, field_select_mask
|
744
744
|
)
|
plain/models/sql/subqueries.py
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
Query subclasses which provide extra functionality beyond simple data retrieval.
|
3
3
|
"""
|
4
4
|
|
5
|
-
from plain.exceptions import FieldError
|
5
|
+
from plain.models.exceptions import FieldError
|
6
6
|
from plain.models.sql.constants import CURSOR, GET_ITERATOR_CHUNK_SIZE, NO_RESULTS
|
7
7
|
from plain.models.sql.query import Query
|
8
8
|
|
@@ -87,13 +87,13 @@ class UpdateQuery(Query):
|
|
87
87
|
direct = (
|
88
88
|
not (field.auto_created and not field.concrete) or not field.concrete
|
89
89
|
)
|
90
|
-
model = field.model
|
90
|
+
model = field.model
|
91
91
|
if not direct or (field.is_relation and field.many_to_many):
|
92
92
|
raise FieldError(
|
93
93
|
f"Cannot update model field {field!r} (only non-relations and "
|
94
94
|
"foreign keys permitted)."
|
95
95
|
)
|
96
|
-
if model is not self.get_meta().
|
96
|
+
if model is not self.get_meta().model:
|
97
97
|
self.add_related_update(model, field, val)
|
98
98
|
continue
|
99
99
|
values_seq.append((field, model, val))
|
plain/models/sql/where.py
CHANGED
@@ -5,7 +5,7 @@ Code to manage the creation and SQL rendering of 'where' constraints.
|
|
5
5
|
import operator
|
6
6
|
from functools import cached_property, reduce
|
7
7
|
|
8
|
-
from plain.exceptions import EmptyResultSet, FullResultSet
|
8
|
+
from plain.models.exceptions import EmptyResultSet, FullResultSet
|
9
9
|
from plain.models.expressions import Case, When
|
10
10
|
from plain.models.lookups import Exact
|
11
11
|
from plain.utils import tree
|