plain.models 0.34.2__py3-none-any.whl → 0.34.4__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 CHANGED
@@ -1,5 +1,26 @@
1
1
  # plain-models changelog
2
2
 
3
+ ## [0.34.4](https://github.com/dropseed/plain/releases/plain-models@0.34.4) (2025-07-02)
4
+
5
+ ### What's changed
6
+
7
+ - The built-in `on_delete` behaviors (`CASCADE`, `PROTECT`, `RESTRICT`, `SET_NULL`, `SET_DEFAULT`, and the callables returned by `SET(...)`) no longer receive the legacy `using` argument. Their signatures are now `(collector, field, sub_objs)` ([20325a1](https://github.com/dropseed/plain/commit/20325a1)).
8
+ - Removed the unused `interprets_empty_strings_as_nulls` backend feature flag and the related fallback logic ([285378c](https://github.com/dropseed/plain/commit/285378c)).
9
+
10
+ ### Upgrade instructions
11
+
12
+ - No changes required
13
+
14
+ ## [0.34.3](https://github.com/dropseed/plain/releases/plain-models@0.34.3) (2025-06-29)
15
+
16
+ ### What's changed
17
+
18
+ - Simplified log output when creating or destroying test databases during test setup. The messages now display the test database name directly and no longer reference the deprecated "alias" terminology ([a543706](https://github.com/dropseed/plain/commit/a543706)).
19
+
20
+ ### Upgrade instructions
21
+
22
+ - No changes required
23
+
3
24
  ## [0.34.2](https://github.com/dropseed/plain/releases/plain-models@0.34.2) (2025-06-27)
4
25
 
5
26
  ### What's changed
@@ -36,9 +36,7 @@ class BaseDatabaseCreation:
36
36
  test_database_name = self._get_test_db_name(prefix)
37
37
 
38
38
  if verbosity >= 1:
39
- self.log(
40
- f"Creating test database for alias {self._get_database_display_str(verbosity, test_database_name)}..."
41
- )
39
+ self.log(f"Creating test database '{test_database_name}'...")
42
40
 
43
41
  self._create_test_db(
44
42
  test_database_name=test_database_name, verbosity=verbosity, autoclobber=True
@@ -127,15 +125,6 @@ class BaseDatabaseCreation:
127
125
  # # because constraint checks were disabled.
128
126
  # self.connection.check_constraints(table_names=table_names)
129
127
 
130
- def _get_database_display_str(self, verbosity, database_name):
131
- """
132
- Return display string for a database for use in various actions.
133
- """
134
- return "'{}'{}".format(
135
- self.connection.alias,
136
- (f" ('{database_name}')") if verbosity >= 2 else "",
137
- )
138
-
139
128
  def _get_test_db_name(self, prefix=""):
140
129
  """
141
130
  Internal implementation - return the name of the test DB that will be
@@ -182,11 +171,7 @@ class BaseDatabaseCreation:
182
171
  try:
183
172
  if verbosity >= 1:
184
173
  self.log(
185
- "Destroying old test database for alias {}...".format(
186
- self._get_database_display_str(
187
- verbosity, test_database_name
188
- ),
189
- )
174
+ f"Destroying old test database '{test_database_name}'..."
190
175
  )
191
176
  cursor.execute(
192
177
  "DROP DATABASE {dbname}".format(**test_db_params)
@@ -211,9 +196,7 @@ class BaseDatabaseCreation:
211
196
  test_database_name = self.connection.settings_dict["NAME"]
212
197
 
213
198
  if verbosity >= 1:
214
- self.log(
215
- f"Destroying test database for alias {self._get_database_display_str(verbosity, test_database_name)}..."
216
- )
199
+ self.log(f"Destroying test database '{test_database_name}'...")
217
200
  self._destroy_test_db(test_database_name, verbosity)
218
201
 
219
202
  # Restore the original database name
@@ -9,9 +9,6 @@ class BaseDatabaseFeatures:
9
9
  empty_fetchmany_value = []
10
10
  update_can_self_select = True
11
11
 
12
- # Does the backend distinguish between '' and None?
13
- interprets_empty_strings_as_nulls = False
14
-
15
12
  # Does the backend support initially deferrable unique constraints?
16
13
  supports_deferrable_unique_constraints = False
17
14
 
@@ -297,14 +297,6 @@ class BaseDatabaseSchemaEditor:
297
297
  else:
298
298
  yield column_default
299
299
  params.append(default_value)
300
- # Oracle treats the empty string ('') as null, so coerce the null
301
- # option whenever '' is a possible value.
302
- if (
303
- field.empty_strings_allowed
304
- and not field.primary_key
305
- and self.connection.features.interprets_empty_strings_as_nulls
306
- ):
307
- null = True
308
300
 
309
301
  if not null:
310
302
  yield "NOT NULL"
@@ -1042,27 +1034,20 @@ class BaseDatabaseSchemaEditor:
1042
1034
  Return a (sql, params) fragment to set a column to null or non-null
1043
1035
  as required by new_field, or None if no changes are required.
1044
1036
  """
1045
- if (
1046
- self.connection.features.interprets_empty_strings_as_nulls
1047
- and new_field.empty_strings_allowed
1048
- ):
1049
- # The field is nullable in the database anyway, leave it alone.
1050
- return
1051
- else:
1052
- new_db_params = new_field.db_parameters(connection=self.connection)
1053
- sql = (
1054
- self.sql_alter_column_null
1055
- if new_field.allow_null
1056
- else self.sql_alter_column_not_null
1057
- )
1058
- return (
1059
- sql
1060
- % {
1061
- "column": self.quote_name(new_field.column),
1062
- "type": new_db_params["type"],
1063
- },
1064
- [],
1065
- )
1037
+ new_db_params = new_field.db_parameters(connection=self.connection)
1038
+ sql = (
1039
+ self.sql_alter_column_null
1040
+ if new_field.allow_null
1041
+ else self.sql_alter_column_not_null
1042
+ )
1043
+ return (
1044
+ sql
1045
+ % {
1046
+ "column": self.quote_name(new_field.column),
1047
+ "type": new_db_params["type"],
1048
+ },
1049
+ [],
1050
+ )
1066
1051
 
1067
1052
  def _alter_column_default_sql(self, model, old_field, new_field, drop=False):
1068
1053
  """
@@ -32,9 +32,7 @@ class DatabaseCreation(BaseDatabaseCreation):
32
32
  if not self.is_in_memory_db(test_database_name):
33
33
  # Erase the old test database file.
34
34
  if verbosity >= 1:
35
- self.log(
36
- f"Destroying old test database for alias {self._get_database_display_str(verbosity, test_database_name)}..."
37
- )
35
+ self.log(f"Destroying old test database '{test_database_name}'...")
38
36
  if os.access(test_database_name, os.F_OK):
39
37
  if not autoclobber:
40
38
  confirm = input(
plain/models/base.py CHANGED
@@ -833,10 +833,7 @@ class Model(metaclass=ModelBase):
833
833
  f = self._meta.get_field(field_name)
834
834
  lookup_value = getattr(self, f.attname)
835
835
  # TODO: Handle multiple backends with different feature flags.
836
- if lookup_value is None or (
837
- lookup_value == ""
838
- and db_connection.features.interprets_empty_strings_as_nulls
839
- ):
836
+ if lookup_value is None:
840
837
  # no value, skip the lookup
841
838
  continue
842
839
  if f.primary_key and not self._state.adding:
@@ -2,7 +2,6 @@ from enum import Enum
2
2
  from types import NoneType
3
3
 
4
4
  from plain.exceptions import FieldError, ValidationError
5
- from plain.models.db import db_connection
6
5
  from plain.models.expressions import Exists, ExpressionList, F, OrderBy
7
6
  from plain.models.indexes import IndexExpression
8
7
  from plain.models.lookups import Exact
@@ -356,10 +355,7 @@ class UniqueConstraint(BaseConstraint):
356
355
  return
357
356
  field = model._meta.get_field(field_name)
358
357
  lookup_value = getattr(instance, field.attname)
359
- if lookup_value is None or (
360
- lookup_value == ""
361
- and db_connection.features.interprets_empty_strings_as_nulls
362
- ):
358
+ if lookup_value is None:
363
359
  # A composite constraint containing NULL value cannot cause
364
360
  # a violation since NULL != NULL in SQL.
365
361
  return
plain/models/deletion.py CHANGED
@@ -24,7 +24,7 @@ class RestrictedError(IntegrityError):
24
24
  super().__init__(msg, restricted_objects)
25
25
 
26
26
 
27
- def CASCADE(collector, field, sub_objs, using):
27
+ def CASCADE(collector, field, sub_objs):
28
28
  collector.collect(
29
29
  sub_objs,
30
30
  source=field.remote_field.model,
@@ -35,7 +35,7 @@ def CASCADE(collector, field, sub_objs, using):
35
35
  collector.add_field_update(field, None, sub_objs)
36
36
 
37
37
 
38
- def PROTECT(collector, field, sub_objs, using):
38
+ def PROTECT(collector, field, sub_objs):
39
39
  raise ProtectedError(
40
40
  f"Cannot delete some instances of model '{field.remote_field.model.__name__}' because they are "
41
41
  f"referenced through a protected foreign key: '{sub_objs[0].__class__.__name__}.{field.name}'",
@@ -43,7 +43,7 @@ def PROTECT(collector, field, sub_objs, using):
43
43
  )
44
44
 
45
45
 
46
- def RESTRICT(collector, field, sub_objs, using):
46
+ def RESTRICT(collector, field, sub_objs):
47
47
  collector.add_restricted_objects(field, sub_objs)
48
48
  collector.add_dependency(field.remote_field.model, field.model)
49
49
 
@@ -51,12 +51,12 @@ def RESTRICT(collector, field, sub_objs, using):
51
51
  def SET(value):
52
52
  if callable(value):
53
53
 
54
- def set_on_delete(collector, field, sub_objs, using):
54
+ def set_on_delete(collector, field, sub_objs):
55
55
  collector.add_field_update(field, value(), sub_objs)
56
56
 
57
57
  else:
58
58
 
59
- def set_on_delete(collector, field, sub_objs, using):
59
+ def set_on_delete(collector, field, sub_objs):
60
60
  collector.add_field_update(field, value, sub_objs)
61
61
 
62
62
  set_on_delete.deconstruct = lambda: ("plain.models.SET", (value,), {})
@@ -64,21 +64,21 @@ def SET(value):
64
64
  return set_on_delete
65
65
 
66
66
 
67
- def SET_NULL(collector, field, sub_objs, using):
67
+ def SET_NULL(collector, field, sub_objs):
68
68
  collector.add_field_update(field, None, sub_objs)
69
69
 
70
70
 
71
71
  SET_NULL.lazy_sub_objs = True
72
72
 
73
73
 
74
- def SET_DEFAULT(collector, field, sub_objs, using):
74
+ def SET_DEFAULT(collector, field, sub_objs):
75
75
  collector.add_field_update(field, field.get_default(), sub_objs)
76
76
 
77
77
 
78
78
  SET_DEFAULT.lazy_sub_objs = True
79
79
 
80
80
 
81
- def DO_NOTHING(collector, field, sub_objs, using):
81
+ def DO_NOTHING(collector, field, sub_objs):
82
82
  pass
83
83
 
84
84
 
@@ -365,11 +365,7 @@ class Field(RegisterLookupMixin):
365
365
  return errors
366
366
 
367
367
  def _check_null_allowed_for_primary_keys(self):
368
- if (
369
- self.primary_key
370
- and self.allow_null
371
- and not db_connection.features.interprets_empty_strings_as_nulls
372
- ):
368
+ if self.primary_key and self.allow_null:
373
369
  # We cannot reliably check this for backends like Oracle which
374
370
  # consider NULL and '' to be equal (and thus set up
375
371
  # character-based fields a little differently).
@@ -885,11 +881,7 @@ class Field(RegisterLookupMixin):
885
881
  return self.default
886
882
  return lambda: self.default
887
883
 
888
- if (
889
- not self.empty_strings_allowed
890
- or self.allow_null
891
- and not db_connection.features.interprets_empty_strings_as_nulls
892
- ):
884
+ if not self.empty_strings_allowed or self.allow_null:
893
885
  return return_None
894
886
  return str # return empty string
895
887
 
@@ -974,11 +974,7 @@ class ForeignKey(ForeignObject):
974
974
 
975
975
  def get_db_prep_save(self, value, connection):
976
976
  if value is None or (
977
- value == ""
978
- and (
979
- not self.target_field.empty_strings_allowed
980
- or connection.features.interprets_empty_strings_as_nulls
981
- )
977
+ value == "" and not self.target_field.empty_strings_allowed
982
978
  ):
983
979
  return None
984
980
  else:
@@ -1019,8 +1015,6 @@ class ForeignKey(ForeignObject):
1019
1015
 
1020
1016
  def get_db_converters(self, connection):
1021
1017
  converters = super().get_db_converters(connection)
1022
- if connection.features.interprets_empty_strings_as_nulls:
1023
- converters += [self.convert_empty_strings]
1024
1018
  return converters
1025
1019
 
1026
1020
  def get_col(self, alias, output_field=None):
@@ -369,15 +369,12 @@ def create_reverse_many_to_one_manager(superclass, rel):
369
369
  """
370
370
  Filter the queryset for the instance this manager is bound to.
371
371
  """
372
- empty_strings_as_null = (
373
- db_connection.features.interprets_empty_strings_as_nulls
374
- )
375
372
  queryset._add_hints(instance=self.instance)
376
373
  queryset._defer_next_filter = True
377
374
  queryset = queryset.filter(**self.core_filters)
378
375
  for field in self.field.foreign_related_fields:
379
376
  val = getattr(self.instance, field.attname)
380
- if val is None or (val == "" and empty_strings_as_null):
377
+ if val is None:
381
378
  return queryset.none()
382
379
  if self.field.many_to_one:
383
380
  # Guard against field-like objects such as GenericRelation
plain/models/forms.py CHANGED
@@ -769,13 +769,7 @@ def modelfield_to_formfield(
769
769
  # Passing max_length to forms.CharField means that the value's length
770
770
  # will be validated twice. This is considered acceptable since we want
771
771
  # the value in the form field (to pass into widget for example).
772
- # TODO: Handle multiple backends with different feature flags.
773
- from plain.models.db import db_connection
774
-
775
- if (
776
- modelfield.allow_null
777
- and not db_connection.features.interprets_empty_strings_as_nulls
778
- ):
772
+ if modelfield.allow_null:
779
773
  defaults["empty_value"] = None
780
774
  return fields.CharField(
781
775
  max_length=modelfield.max_length,
plain/models/sql/query.py CHANGED
@@ -1233,16 +1233,6 @@ class Query(BaseExpression):
1233
1233
  raise ValueError("Cannot use None as a query value")
1234
1234
  return lhs.get_lookup("isnull")(lhs, True)
1235
1235
 
1236
- # For Oracle '' is equivalent to null. The check must be done at this
1237
- # stage because join promotion can't be done in the compiler. A similar
1238
- # thing is done in is_nullable(), too.
1239
- if (
1240
- lookup_name == "exact"
1241
- and lookup.rhs == ""
1242
- and db_connection.features.interprets_empty_strings_as_nulls
1243
- ):
1244
- return lhs.get_lookup("isnull")(lhs, True)
1245
-
1246
1236
  return lookup
1247
1237
 
1248
1238
  def try_transform(self, lhs, name):
@@ -2466,20 +2456,11 @@ class Query(BaseExpression):
2466
2456
  return trimmed_prefix, contains_louter
2467
2457
 
2468
2458
  def is_nullable(self, field):
2469
- """
2470
- Check if the given field should be treated as nullable.
2471
-
2472
- Some backends treat '' as null and Plain treats such fields as
2473
- nullable for those backends. In such situations field.allow_null can be
2474
- False even if we should treat the field as nullable.
2475
- """
2459
+ """Check if the given field should be treated as nullable."""
2476
2460
  # QuerySet does not have knowledge of which connection is going to be
2477
2461
  # used. For the single-database setup we always reference the default
2478
2462
  # connection here.
2479
- return field.allow_null or (
2480
- field.empty_strings_allowed
2481
- and db_connection.features.interprets_empty_strings_as_nulls
2482
- )
2463
+ return field.allow_null
2483
2464
 
2484
2465
 
2485
2466
  def get_order_dir(field, default="ASC"):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain.models
3
- Version: 0.34.2
3
+ Version: 0.34.4
4
4
  Summary: Database models for Plain.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-File: LICENSE
@@ -1,22 +1,22 @@
1
- plain/models/CHANGELOG.md,sha256=r04vS3MHdGDOKyt4OTk9EUw0BFysg9Ci8_hd6KbeDD4,2196
1
+ plain/models/CHANGELOG.md,sha256=23hduuGGlZJVuZaW57q7mDNH3eJme2JBkyqooogAQVk,3260
2
2
  plain/models/README.md,sha256=vsZPev3Fna-Irdcs3-wrOcAoII5LOhXdcWLBMT87CS0,1626
3
3
  plain/models/__init__.py,sha256=dnU6MOXs3lGoK31nLWjCqbf7zigkaUccomchz9lNDJ8,2950
4
4
  plain/models/aggregates.py,sha256=P0mhsMl1VZt2CVHMuCHnNI8SxZ9citjDLEgioN6NOpo,7240
5
- plain/models/base.py,sha256=rjPWtHI0YzTJ--uRgQ-CrMK-iNhttNFAWWWC2h4pqis,68095
5
+ plain/models/base.py,sha256=8-F9DvSF5s2_zoGyEmZU5xg9GdEigthVT0HENv9iigI,67952
6
6
  plain/models/cli.py,sha256=-K5ZrMbwL-fcUOze64_U4uOPpCuppa-ibdoOaCFvBF4,43966
7
7
  plain/models/config.py,sha256=OF7eIEtXNZyGwgc3eMEpb5uEAup5RXeT-0um60dfBeU,636
8
8
  plain/models/connections.py,sha256=RBNa2FZ0x3C9un6PaYL-IYzH_OesRSpdHNGKvYHGiOM,2276
9
9
  plain/models/constants.py,sha256=ndnj9TOTKW0p4YcIPLOLEbsH6mOgFi6B1-rIzr_iwwU,210
10
- plain/models/constraints.py,sha256=ZECMnw6urCjRu6XLDjXE5zuFdeZOE-hzowCAa8N8xGU,16967
10
+ plain/models/constraints.py,sha256=iMQj0AoExqTKEgn_Z3T2LKIlKC2TREPFwHxjvbc2iGU,16782
11
11
  plain/models/database_url.py,sha256=iidKVhOylf5N6t1EMPRySRQiv6LiuRjYRECB_UJ3MI8,6419
12
12
  plain/models/db.py,sha256=FpdfLYrRX2THUzDy4QdJ_OpSo9IFKLerZIEQ-T2x8zA,1348
13
13
  plain/models/default_settings.py,sha256=cDym1o_DtHySWgDRIdjgEM0YxjgYU51ZqzWVA3vpzTk,569
14
- plain/models/deletion.py,sha256=izvpGwvP8xxmuNVKvuYaeAKFD03FZMMfjkRUmMBiTDI,17631
14
+ plain/models/deletion.py,sha256=iyVKgbEdphncpJiwofNaXPa72z301hp2bmRHp1RQFSA,17575
15
15
  plain/models/entrypoints.py,sha256=EC14mW19tK9dCumaNHnv4_9jQV8jomQ8jXy8Ib89VBw,191
16
16
  plain/models/enums.py,sha256=Zr-JKt2aeYsSADtAm69fDRfajS7jYwop2vWQVLJ9YYI,2726
17
17
  plain/models/exceptions.py,sha256=IqzK60-hY3TYsgOMxlWwgpVa21E7ydC-gqUG4tNvVJc,2042
18
18
  plain/models/expressions.py,sha256=hN6sfOxqxpP0qmYOUotsFAAn2-bnl35iHwyINyXA7CI,62763
19
- plain/models/forms.py,sha256=M53zESGUdkJk6B6GD6vcGQ_aVvqF3S2eKBgcmMdvHyI,28548
19
+ plain/models/forms.py,sha256=tyLRWwbC0CGLYinsFlnGiTjjjKY3kFSqL_MOuJJ5HPs,28325
20
20
  plain/models/indexes.py,sha256=fazIZPJgCX5_Bhwk7MQy3YbWOxpHvaCe1dDLGGldTuY,11540
21
21
  plain/models/lookups.py,sha256=0tbuMBpd4DlTUeO0IdZPtSO2GcjsSgcbRcj5lYfe87M,24776
22
22
  plain/models/manager.py,sha256=zc2W-vTTk3zkDXCds5-TCXgLhVmM4PdQb-qtu-njeLQ,5827
@@ -33,11 +33,11 @@ plain/models/backends/utils.py,sha256=QFmpqe1FATF7KcLc00OhZbQzM_L9dPvtqptXe4hU4F
33
33
  plain/models/backends/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
34
  plain/models/backends/base/base.py,sha256=I5040pUAe7-yNTb9wfMNOYjeiFQLZ5dcRI4rtmVKJ04,26457
35
35
  plain/models/backends/base/client.py,sha256=90Ffs6zZYCli3tJjwsPH8TItZ8tz1Pp-zhQa-EpsNqc,937
36
- plain/models/backends/base/creation.py,sha256=idyE4g7uhqPWmTf9oMlovpoIqQaZFv5fvQ-DGnqKAYM,10029
37
- plain/models/backends/base/features.py,sha256=nHUkFjKSx_w9QwD4l-jXP_zotvspy9o6ayn-AHzzrHI,7959
36
+ plain/models/backends/base/creation.py,sha256=T8JaQ67KOtp6YIPksrmOa8BF9oTaTPXgKB5ct6bxh9E,9352
37
+ plain/models/backends/base/features.py,sha256=1AehdhpeC7VobhggwpeXIt7HJNY2EWY700j4gYX8Xjs,7856
38
38
  plain/models/backends/base/introspection.py,sha256=8icKf9h8y4kobmyrbo8JWTDcpQIAt4oS_4FtCnY7FqQ,6815
39
39
  plain/models/backends/base/operations.py,sha256=Y08cS7IZwYXMKVUoEpBCjyOTh1PW2OShoRU9TZdipss,25740
40
- plain/models/backends/base/schema.py,sha256=eJIeoN1nm7abIw_2eKFxeckcZHldixgvDlgCTwvb7GI,65649
40
+ plain/models/backends/base/schema.py,sha256=1dLiVNz1huv8xJo1JphgfWfhXXZ-YGw_MgZ6eWazKQA,65016
41
41
  plain/models/backends/base/validation.py,sha256=2zpI11hyUJr0I0cA1xmvoFwQVdZ-7_1T2F11TpQ0Rkk,1067
42
42
  plain/models/backends/mysql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
43
  plain/models/backends/mysql/base.py,sha256=9PEaRvRcU9MBfir-s_rNooemDmjQQpfzB1DxJJdmC14,15985
@@ -61,7 +61,7 @@ plain/models/backends/sqlite3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
61
61
  plain/models/backends/sqlite3/_functions.py,sha256=XsohPZN-xFEEmC28stQzAiSMvE0nHJ1cMHfL2Ze72vI,14317
62
62
  plain/models/backends/sqlite3/base.py,sha256=h0nFOR89IqFRnBLgjKLPf9eutHOQPmpiatjt4ZjlU34,13265
63
63
  plain/models/backends/sqlite3/client.py,sha256=dvxY10LFJHKY6ykOuCE6e45Wo4fAH4IPDtNCH3Wvd34,324
64
- plain/models/backends/sqlite3/creation.py,sha256=zNAJRkr--ZKJv8QeJWEaYAh8pLPPBK-dclHgelAMn6M,2877
64
+ plain/models/backends/sqlite3/creation.py,sha256=dH4rqZj79TCMHmaBash4I_io15QCxnam92fuWrRK_R8,2788
65
65
  plain/models/backends/sqlite3/features.py,sha256=xbGiBom7Kh0xNTLZrFmTQ32C7M8q8UEmyi6hoBd25kE,2326
66
66
  plain/models/backends/sqlite3/introspection.py,sha256=RMzb8RUfNUvrcbcmgIKjxwp5D2uoth4-eJF-bduBo2o,17286
67
67
  plain/models/backends/sqlite3/operations.py,sha256=K2PFCsvzGhBrPEzz1AXFenge2B4Ap8lsQAABsC4e_UI,15302
@@ -70,11 +70,11 @@ plain/models/backups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
70
70
  plain/models/backups/cli.py,sha256=du_751qWPtJT7C3GF_nLfHucMoUzlUOz9OKUwqHQ16s,2990
71
71
  plain/models/backups/clients.py,sha256=WQ4X4KrkNeiKYJcpGRwnfRiAeeyduHWEnq4tA4mtjvw,4047
72
72
  plain/models/backups/core.py,sha256=09IZUhBEe1Yej3PC8AidtkaI0c8tt7VnqGBCWK-WrFg,3318
73
- plain/models/fields/__init__.py,sha256=fZXZzsvFoIEte-0XSdKjYhkr3mqZ2NqjFD9KPU_HmxI,80319
73
+ plain/models/fields/__init__.py,sha256=b0qggzhZf89cXSwokr6rikWyF6kKPTuceIT3pI1Rz3s,80093
74
74
  plain/models/fields/json.py,sha256=OdGW4EYBSHQgkuugB-EiIXOqGstUqcMKUvOTOVUHqEQ,18049
75
75
  plain/models/fields/mixins.py,sha256=K_ocrSbb6pPuGwYZeqgzoZskwCIMFIB6IV3T5CrU5J0,1805
76
- plain/models/fields/related.py,sha256=v3MH00jy2dcqk8bnYGmABnXIr5OMJ413V9qQL0wej2s,60321
77
- plain/models/fields/related_descriptors.py,sha256=UKwyJi7jGGFO373nPSfX20xOIxo460Xm9Zf-qqZ7Sh8,38703
76
+ plain/models/fields/related.py,sha256=O2sMK-yAeos2AHQwB1ssy9FLQU3F-zyTvPmUYIm_Qj4,60083
77
+ plain/models/fields/related_descriptors.py,sha256=RD5764epSUbs-PFUAd_4xcZgbhLBBhgKuMy-5XMPbf8,38537
78
78
  plain/models/fields/related_lookups.py,sha256=AyAtd5iK_MMkvsQxsFznMCv36QtLoT9NMLLp0v4tDwQ,7785
79
79
  plain/models/fields/reverse_related.py,sha256=PGEFus3ov_0U3W8Ijj1MZlYoFrhUhFllZ8fpZLggvR8,11070
80
80
  plain/models/functions/__init__.py,sha256=aglCm_JtzDYk2KmxubDN_78CGG3JCfRWnfJ74Oj5YJ4,2658
@@ -107,14 +107,14 @@ plain/models/sql/__init__.py,sha256=FoRCcab-kh_XY8C4eldgLy9-zuk-M63Nyi9cFsYjclU,
107
107
  plain/models/sql/compiler.py,sha256=MrwiVKfWxk_fL_cwY1exiM7wbnasIfcfh_4-Q1XKnlA,84734
108
108
  plain/models/sql/constants.py,sha256=usb1LSh9WNGPsurWAGppDkV0wYJJg5GEegKibQdS718,533
109
109
  plain/models/sql/datastructures.py,sha256=FC88CVCukLyU621JrmKLBhmgvotEHgAhIOYfVvJpuR0,7084
110
- plain/models/sql/query.py,sha256=gsCBVo5l3yJusukX2xarD1pGoOD69M2W3X3YGx1YjgI,109508
110
+ plain/models/sql/query.py,sha256=jSnzBoM66dTR-4aJpO-T2ksOc5PSeIQ07ToPEzYj58U,108723
111
111
  plain/models/sql/subqueries.py,sha256=JkVjYuWyEBpSDFNMOH00RmXxe8V4cERjUQ_ypGepqyo,5847
112
112
  plain/models/sql/where.py,sha256=ezE9Clt2BmKo-I7ARsgqZ_aVA-1UdayCwr6ULSWZL6c,12635
113
113
  plain/models/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
114
  plain/models/test/pytest.py,sha256=5mxY1MHqfCFJ7G39W1DuE0vCHfsfehQQmOyE6vI6caw,3323
115
115
  plain/models/test/utils.py,sha256=MxBNWoGMtwAtka7LbxWgilgzv7T5qqJL8ystF2SDJrs,345
116
- plain_models-0.34.2.dist-info/METADATA,sha256=wsRt3LgaqNF--XdOjUktCcbRG2BauaToDhki6TLukl4,1921
117
- plain_models-0.34.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
118
- plain_models-0.34.2.dist-info/entry_points.txt,sha256=IYJAW9MpL3PXyXFWmKmALagAGXC_5rzBn2eEGJlcV04,112
119
- plain_models-0.34.2.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
120
- plain_models-0.34.2.dist-info/RECORD,,
116
+ plain_models-0.34.4.dist-info/METADATA,sha256=lIwA7kJww6io4OCqeWiM0THgYzG7Qf-7hlDtl6IainA,1921
117
+ plain_models-0.34.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
118
+ plain_models-0.34.4.dist-info/entry_points.txt,sha256=IYJAW9MpL3PXyXFWmKmALagAGXC_5rzBn2eEGJlcV04,112
119
+ plain_models-0.34.4.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
120
+ plain_models-0.34.4.dist-info/RECORD,,