plain.models 0.33.1__py3-none-any.whl → 0.34.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 (56) hide show
  1. plain/models/CHANGELOG.md +17 -0
  2. plain/models/README.md +8 -10
  3. plain/models/__init__.py +2 -6
  4. plain/models/backends/base/base.py +10 -18
  5. plain/models/backends/base/creation.py +3 -4
  6. plain/models/backends/base/introspection.py +2 -3
  7. plain/models/backends/base/schema.py +3 -9
  8. plain/models/backends/mysql/validation.py +1 -1
  9. plain/models/backends/postgresql/base.py +15 -23
  10. plain/models/backends/postgresql/schema.py +0 -2
  11. plain/models/backends/sqlite3/base.py +1 -1
  12. plain/models/backends/sqlite3/creation.py +2 -2
  13. plain/models/backends/sqlite3/features.py +1 -1
  14. plain/models/backends/sqlite3/schema.py +1 -1
  15. plain/models/backends/utils.py +2 -6
  16. plain/models/backups/core.py +15 -22
  17. plain/models/base.py +179 -225
  18. plain/models/cli.py +25 -62
  19. plain/models/connections.py +48 -165
  20. plain/models/constraints.py +10 -10
  21. plain/models/db.py +7 -15
  22. plain/models/default_settings.py +13 -20
  23. plain/models/deletion.py +14 -16
  24. plain/models/expressions.py +7 -10
  25. plain/models/fields/__init__.py +56 -76
  26. plain/models/fields/json.py +9 -12
  27. plain/models/fields/related.py +5 -17
  28. plain/models/fields/related_descriptors.py +43 -95
  29. plain/models/forms.py +2 -4
  30. plain/models/indexes.py +2 -3
  31. plain/models/lookups.py +0 -7
  32. plain/models/manager.py +1 -14
  33. plain/models/migrations/executor.py +0 -16
  34. plain/models/migrations/loader.py +1 -1
  35. plain/models/migrations/migration.py +1 -1
  36. plain/models/migrations/operations/base.py +4 -11
  37. plain/models/migrations/operations/fields.py +4 -4
  38. plain/models/migrations/operations/models.py +10 -10
  39. plain/models/migrations/operations/special.py +6 -14
  40. plain/models/migrations/recorder.py +1 -1
  41. plain/models/options.py +4 -7
  42. plain/models/preflight.py +25 -44
  43. plain/models/query.py +47 -102
  44. plain/models/query_utils.py +4 -4
  45. plain/models/sql/compiler.py +7 -11
  46. plain/models/sql/query.py +32 -42
  47. plain/models/sql/subqueries.py +6 -8
  48. plain/models/sql/where.py +1 -1
  49. plain/models/test/pytest.py +21 -32
  50. plain/models/test/utils.py +7 -143
  51. plain/models/transaction.py +66 -164
  52. {plain_models-0.33.1.dist-info → plain_models-0.34.0.dist-info}/METADATA +9 -11
  53. {plain_models-0.33.1.dist-info → plain_models-0.34.0.dist-info}/RECORD +56 -55
  54. {plain_models-0.33.1.dist-info → plain_models-0.34.0.dist-info}/WHEEL +0 -0
  55. {plain_models-0.33.1.dist-info → plain_models-0.34.0.dist-info}/entry_points.txt +0 -0
  56. {plain_models-0.33.1.dist-info → plain_models-0.34.0.dist-info}/licenses/LICENSE +0 -0
plain/models/cli.py CHANGED
@@ -14,7 +14,7 @@ from plain.utils.text import Truncator
14
14
  from . import migrations
15
15
  from .backups.cli import cli as backups_cli
16
16
  from .backups.cli import create_backup
17
- from .db import DEFAULT_DB_ALIAS, OperationalError, connections, router
17
+ from .db import OperationalError, db_connection
18
18
  from .migrations.autodetector import MigrationAutodetector
19
19
  from .migrations.executor import MigrationExecutor
20
20
  from .migrations.loader import AmbiguityError, MigrationLoader
@@ -42,27 +42,18 @@ cli.add_command(backups_cli)
42
42
 
43
43
 
44
44
  @cli.command()
45
- @click.option(
46
- "--database",
47
- default=DEFAULT_DB_ALIAS,
48
- help=(
49
- "Nominates a database onto which to open a shell. Defaults to the "
50
- '"default" database.'
51
- ),
52
- )
53
45
  @click.argument("parameters", nargs=-1)
54
- def db_shell(database, parameters):
46
+ def db_shell(parameters):
55
47
  """Runs the command-line client for specified database, or the default database if none is provided."""
56
- connection = connections[database]
57
48
  try:
58
- connection.client.runshell(parameters)
49
+ db_connection.client.runshell(parameters)
59
50
  except FileNotFoundError:
60
51
  # Note that we're assuming the FileNotFoundError relates to the
61
52
  # command missing. It could be raised for some other reason, in
62
53
  # which case this error message would be inaccurate. Still, this
63
54
  # message catches the common case.
64
55
  click.secho(
65
- f"You appear not to have the {connection.client.executable_name!r} program installed or on your path.",
56
+ f"You appear not to have the {db_connection.client.executable_name!r} program installed or on your path.",
66
57
  fg="red",
67
58
  err=True,
68
59
  )
@@ -85,24 +76,23 @@ def db_wait():
85
76
  attempts = 0
86
77
  while True:
87
78
  attempts += 1
88
- waiting_for = []
79
+ waiting_for = False
89
80
 
90
- for conn in connections.all():
91
- try:
92
- conn.ensure_connection()
93
- except OperationalError:
94
- waiting_for.append(conn.alias)
81
+ try:
82
+ db_connection.ensure_connection()
83
+ except OperationalError:
84
+ waiting_for = True
95
85
 
96
86
  if waiting_for:
97
87
  if attempts > 1:
98
88
  # After the first attempt, start printing them
99
89
  click.secho(
100
- f"Waiting for database (attempt {attempts}): {', '.join(waiting_for)}",
90
+ f"Waiting for database (attempt {attempts})",
101
91
  fg="yellow",
102
92
  )
103
93
  time.sleep(1.5)
104
94
  else:
105
- click.secho(f"Database ready: {', '.join(connections)}", fg="green")
95
+ click.secho("Database ready", fg="green")
106
96
  break
107
97
 
108
98
 
@@ -318,21 +308,8 @@ def makemigrations(
318
308
  loader = MigrationLoader(None, ignore_no_migrations=True)
319
309
 
320
310
  # Raise an error if any migrations are applied before their dependencies.
321
- consistency_check_labels = {
322
- config.package_label for config in packages_registry.get_package_configs()
323
- }
324
- # Non-default databases are only checked if database routers used.
325
- aliases_to_check = connections if settings.DATABASE_ROUTERS else [DEFAULT_DB_ALIAS]
326
- for alias in sorted(aliases_to_check):
327
- connection = connections[alias]
328
- if any(
329
- router.allow_migrate(
330
- connection.alias, package_label, model_name=model._meta.object_name
331
- )
332
- for package_label in consistency_check_labels
333
- for model in models_registry.get_models(package_label=package_label)
334
- ):
335
- loader.check_consistent_history(connection)
311
+ # Only the default db_connection is supported.
312
+ loader.check_consistent_history(db_connection)
336
313
 
337
314
  # Check for conflicts
338
315
  conflicts = loader.detect_conflicts()
@@ -422,11 +399,6 @@ def makemigrations(
422
399
  @cli.command()
423
400
  @click.argument("package_label", required=False)
424
401
  @click.argument("migration_name", required=False)
425
- @click.option(
426
- "--database",
427
- default=DEFAULT_DB_ALIAS,
428
- help="Nominates a database to synchronize. Defaults to the 'default' database.",
429
- )
430
402
  @click.option(
431
403
  "--fake", is_flag=True, help="Mark migrations as run without actually running them."
432
404
  )
@@ -468,7 +440,6 @@ def makemigrations(
468
440
  def migrate(
469
441
  package_label,
470
442
  migration_name,
471
- database,
472
443
  fake,
473
444
  fake_initial,
474
445
  plan,
@@ -512,16 +483,14 @@ def migrate(
512
483
  return prefix + operation.describe() + truncated.chars(40), is_error
513
484
 
514
485
  # Get the database we're operating from
515
- connection = connections[database]
516
-
517
486
  # Hook for backends needing any database preparation
518
- connection.prepare_database()
487
+ db_connection.prepare_database()
519
488
 
520
489
  # Work out which packages have migrations and which do not
521
- executor = MigrationExecutor(connection, migration_progress_callback)
490
+ executor = MigrationExecutor(db_connection, migration_progress_callback)
522
491
 
523
492
  # Raise an error if any migrations are applied before their dependencies.
524
- executor.loader.check_consistent_history(connection)
493
+ executor.loader.check_consistent_history(db_connection)
525
494
 
526
495
  # Before anything else, see if there's conflicting packages and drop out
527
496
  # hard if there are any
@@ -864,11 +833,6 @@ def optimize_migration(package_label, migration_name, check, verbosity):
864
833
 
865
834
  @cli.command()
866
835
  @click.argument("package_labels", nargs=-1)
867
- @click.option(
868
- "--database",
869
- default=DEFAULT_DB_ALIAS,
870
- help="Nominates a database to show migrations for. Defaults to the 'default' database.",
871
- )
872
836
  @click.option(
873
837
  "--format",
874
838
  type=click.Choice(["list", "plan"]),
@@ -882,7 +846,7 @@ def optimize_migration(package_label, migration_name, check, verbosity):
882
846
  default=1,
883
847
  help="Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output",
884
848
  )
885
- def show_migrations(package_labels, database, format, verbosity):
849
+ def show_migrations(package_labels, format, verbosity):
886
850
  """Shows all available migrations for the current project"""
887
851
 
888
852
  def _validate_package_names(package_names):
@@ -896,14 +860,14 @@ def show_migrations(package_labels, database, format, verbosity):
896
860
  if has_bad_names:
897
861
  sys.exit(2)
898
862
 
899
- def show_list(connection, package_names):
863
+ def show_list(db_connection, package_names):
900
864
  """
901
865
  Show a list of all migrations on the system, or only those of
902
866
  some named packages.
903
867
  """
904
868
  # Load migrations from disk/DB
905
- loader = MigrationLoader(connection, ignore_no_migrations=True)
906
- recorder = MigrationRecorder(connection)
869
+ loader = MigrationLoader(db_connection, ignore_no_migrations=True)
870
+ recorder = MigrationRecorder(db_connection)
907
871
  recorded_migrations = recorder.applied_migrations()
908
872
 
909
873
  graph = loader.graph
@@ -972,13 +936,13 @@ def show_migrations(package_labels, database, format, verbosity):
972
936
  for name in sorted(prunable_by_package[package]):
973
937
  click.echo(f" - {name}")
974
938
 
975
- def show_plan(connection, package_names):
939
+ def show_plan(db_connection, package_names):
976
940
  """
977
941
  Show all known migrations (or only those of the specified package_names)
978
942
  in the order they will be applied.
979
943
  """
980
944
  # Load migrations from disk/DB
981
- loader = MigrationLoader(connection)
945
+ loader = MigrationLoader(db_connection)
982
946
  graph = loader.graph
983
947
  if package_names:
984
948
  _validate_package_names(package_names)
@@ -1017,12 +981,11 @@ def show_migrations(package_labels, database, format, verbosity):
1017
981
  click.secho("(no migrations)", fg="red")
1018
982
 
1019
983
  # Get the database we're operating from
1020
- connection = connections[database]
1021
984
 
1022
985
  if format == "plan":
1023
- show_plan(connection, package_labels)
986
+ show_plan(db_connection, package_labels)
1024
987
  else:
1025
- show_list(connection, package_labels)
988
+ show_list(db_connection, package_labels)
1026
989
 
1027
990
 
1028
991
  @cli.command()
@@ -1082,7 +1045,7 @@ def squash_migrations(
1082
1045
  raise click.ClickException(str(err))
1083
1046
 
1084
1047
  # Load the current graph state, check the app and migration they asked for exists
1085
- loader = MigrationLoader(connections[DEFAULT_DB_ALIAS])
1048
+ loader = MigrationLoader(db_connection)
1086
1049
  if package_label not in loader.migrated_packages:
1087
1050
  raise click.ClickException(
1088
1051
  f"Package '{package_label}' does not have migrations (so squashmigrations on it makes no sense)"
@@ -1,15 +1,8 @@
1
- from functools import cached_property
2
1
  from importlib import import_module
3
2
  from threading import local
4
3
  from typing import Any, TypedDict
5
4
 
6
- from plain.exceptions import ImproperlyConfigured
7
5
  from plain.runtime import settings as plain_settings
8
- from plain.utils.module_loading import import_string
9
-
10
- from .exceptions import ConnectionDoesNotExist
11
-
12
- DEFAULT_DB_ALIAS = "default"
13
6
 
14
7
 
15
8
  class DatabaseConfig(TypedDict, total=False):
@@ -28,167 +21,57 @@ class DatabaseConfig(TypedDict, total=False):
28
21
  USER: str
29
22
 
30
23
 
31
- class ConnectionHandler:
32
- """
33
- Handler for database connections. Provides lazy connection creation
34
- and convenience methods for managing multiple database connections.
35
- """
24
+ class DatabaseConnection:
25
+ """Lazy access to the single configured database connection."""
36
26
 
37
- def __init__(self):
38
- self._settings: dict[str, DatabaseConfig] = {}
39
- self._connections = local()
27
+ __slots__ = ("_settings", "_local")
40
28
 
41
- @cached_property
42
- def settings(self) -> DatabaseConfig:
43
- self._settings = self.configure_settings()
44
- return self._settings
29
+ def __init__(self):
30
+ self._settings: DatabaseConfig = {}
31
+ self._local = local()
45
32
 
46
33
  def configure_settings(self) -> DatabaseConfig:
47
- databases = plain_settings.DATABASES
48
-
49
- if DEFAULT_DB_ALIAS not in databases:
50
- raise ImproperlyConfigured(
51
- f"You must define a '{DEFAULT_DB_ALIAS}' database."
52
- )
53
-
54
- # Configure default settings.
55
- for conn in databases.values():
56
- conn.setdefault("AUTOCOMMIT", True)
57
- conn.setdefault("CONN_MAX_AGE", 0)
58
- conn.setdefault("CONN_HEALTH_CHECKS", False)
59
- conn.setdefault("OPTIONS", {})
60
- conn.setdefault("TIME_ZONE", None)
61
- for setting in ["NAME", "USER", "PASSWORD", "HOST", "PORT"]:
62
- conn.setdefault(setting, "")
63
-
64
- test_settings = conn.setdefault("TEST", {})
65
- default_test_settings = [
66
- ("CHARSET", None),
67
- ("COLLATION", None),
68
- ("MIRROR", None),
69
- ("NAME", None),
70
- ]
71
- for key, value in default_test_settings:
72
- test_settings.setdefault(key, value)
73
-
74
- return databases
75
-
76
- def create_connection(self, alias):
77
- database_config = self.settings[alias]
78
- backend = import_module(f"{database_config['ENGINE']}.base")
79
- return backend.DatabaseWrapper(database_config, alias)
80
-
81
- def __getitem__(self, alias):
82
- try:
83
- return getattr(self._connections, alias)
84
- except AttributeError:
85
- if alias not in self.settings:
86
- raise ConnectionDoesNotExist(f"The connection '{alias}' doesn't exist.")
87
- conn = self.create_connection(alias)
88
- setattr(self._connections, alias, conn)
89
- return conn
90
-
91
- def __setitem__(self, key, value):
92
- setattr(self._connections, key, value)
93
-
94
- def __delitem__(self, key):
95
- delattr(self._connections, key)
96
-
97
- def __iter__(self):
98
- return iter(self.settings)
99
-
100
- def all(self, initialized_only=False):
101
- return [
102
- self[alias]
103
- for alias in self
104
- # If initialized_only is True, return only initialized connections.
105
- if not initialized_only or hasattr(self._connections, alias)
34
+ database = plain_settings.DATABASE
35
+
36
+ database.setdefault("AUTOCOMMIT", True)
37
+ database.setdefault("CONN_MAX_AGE", 0)
38
+ database.setdefault("CONN_HEALTH_CHECKS", False)
39
+ database.setdefault("OPTIONS", {})
40
+ database.setdefault("TIME_ZONE", None)
41
+ for setting in ["NAME", "USER", "PASSWORD", "HOST", "PORT"]:
42
+ database.setdefault(setting, "")
43
+
44
+ test_settings = database.setdefault("TEST", {})
45
+ default_test_settings = [
46
+ ("CHARSET", None),
47
+ ("COLLATION", None),
48
+ ("MIRROR", None),
49
+ ("NAME", None),
106
50
  ]
51
+ for key, value in default_test_settings:
52
+ test_settings.setdefault(key, value)
53
+
54
+ return database
55
+
56
+ def create_connection(self):
57
+ database_config = self.configure_settings()
58
+ backend = import_module(f"{database_config['ENGINE']}.base")
59
+ return backend.DatabaseWrapper(database_config)
60
+
61
+ def has_connection(self):
62
+ return hasattr(self._local, "conn")
63
+
64
+ def __getattr__(self, attr):
65
+ if not self.has_connection():
66
+ self._local.conn = self.create_connection()
67
+
68
+ return getattr(self._local.conn, attr)
69
+
70
+ def __setattr__(self, name, value):
71
+ if name.startswith("_"):
72
+ super().__setattr__(name, value)
73
+ else:
74
+ if not self.has_connection():
75
+ self._local.conn = self.create_connection()
107
76
 
108
- def close_all(self):
109
- for conn in self.all(initialized_only=True):
110
- conn.close()
111
-
112
-
113
- class ConnectionRouter:
114
- def __init__(self, routers=None):
115
- """
116
- If routers is not specified, default to settings.DATABASE_ROUTERS.
117
- """
118
- self._routers = routers
119
-
120
- @cached_property
121
- def routers(self):
122
- if self._routers is None:
123
- self._routers = plain_settings.DATABASE_ROUTERS
124
- routers = []
125
- for r in self._routers:
126
- if isinstance(r, str):
127
- router = import_string(r)()
128
- else:
129
- router = r
130
- routers.append(router)
131
- return routers
132
-
133
- def _router_func(action):
134
- def _route_db(self, model, **hints):
135
- chosen_db = None
136
- for router in self.routers:
137
- try:
138
- method = getattr(router, action)
139
- except AttributeError:
140
- # If the router doesn't have a method, skip to the next one.
141
- pass
142
- else:
143
- chosen_db = method(model, **hints)
144
- if chosen_db:
145
- return chosen_db
146
- instance = hints.get("instance")
147
- if instance is not None and instance._state.db:
148
- return instance._state.db
149
- return DEFAULT_DB_ALIAS
150
-
151
- return _route_db
152
-
153
- db_for_read = _router_func("db_for_read")
154
- db_for_write = _router_func("db_for_write")
155
-
156
- def allow_relation(self, obj1, obj2, **hints):
157
- for router in self.routers:
158
- try:
159
- method = router.allow_relation
160
- except AttributeError:
161
- # If the router doesn't have a method, skip to the next one.
162
- pass
163
- else:
164
- allow = method(obj1, obj2, **hints)
165
- if allow is not None:
166
- return allow
167
- return obj1._state.db == obj2._state.db
168
-
169
- def allow_migrate(self, db, package_label, **hints):
170
- for router in self.routers:
171
- try:
172
- method = router.allow_migrate
173
- except AttributeError:
174
- # If the router doesn't have a method, skip to the next one.
175
- continue
176
-
177
- allow = method(db, package_label, **hints)
178
-
179
- if allow is not None:
180
- return allow
181
- return True
182
-
183
- def allow_migrate_model(self, db, model):
184
- return self.allow_migrate(
185
- db,
186
- model._meta.package_label,
187
- model_name=model._meta.model_name,
188
- model=model,
189
- )
190
-
191
- def get_migratable_models(self, models_registry, package_label, db):
192
- """Return app models allowed to be migrated on provided db."""
193
- models = models_registry.get_models(package_label=package_label)
194
- return [model for model in models if self.allow_migrate_model(db, model)]
77
+ setattr(self._local.conn, name, value)
@@ -2,7 +2,7 @@ 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 DEFAULT_DB_ALIAS, connections
5
+ from plain.models.db import db_connection
6
6
  from plain.models.expressions import Exists, ExpressionList, F, OrderBy
7
7
  from plain.models.indexes import IndexExpression
8
8
  from plain.models.lookups import Exact
@@ -41,7 +41,7 @@ class BaseConstraint:
41
41
  def remove_sql(self, model, schema_editor):
42
42
  raise NotImplementedError("This method must be implemented by a subclass.")
43
43
 
44
- def validate(self, model, instance, exclude=None, using=DEFAULT_DB_ALIAS):
44
+ def validate(self, model, instance, exclude=None):
45
45
  raise NotImplementedError("This method must be implemented by a subclass.")
46
46
 
47
47
  def get_violation_error_message(self):
@@ -83,7 +83,7 @@ class CheckConstraint(BaseConstraint):
83
83
  def _get_check_sql(self, model, schema_editor):
84
84
  query = Query(model=model, alias_cols=False)
85
85
  where = query.build_where(self.check)
86
- compiler = query.get_compiler(connection=schema_editor.connection)
86
+ compiler = query.get_compiler()
87
87
  sql, params = where.as_sql(compiler, schema_editor.connection)
88
88
  return sql % tuple(schema_editor.quote_value(p) for p in params)
89
89
 
@@ -98,10 +98,10 @@ class CheckConstraint(BaseConstraint):
98
98
  def remove_sql(self, model, schema_editor):
99
99
  return schema_editor._delete_check_sql(model, self.name)
100
100
 
101
- def validate(self, model, instance, exclude=None, using=DEFAULT_DB_ALIAS):
101
+ def validate(self, model, instance, exclude=None):
102
102
  against = instance._get_field_value_map(meta=model._meta, exclude=exclude)
103
103
  try:
104
- if not Q(self.check).check(against, using=using):
104
+ if not Q(self.check).check(against):
105
105
  raise ValidationError(
106
106
  self.get_violation_error_message(), code=self.violation_error_code
107
107
  )
@@ -227,7 +227,7 @@ class UniqueConstraint(BaseConstraint):
227
227
  return None
228
228
  query = Query(model=model, alias_cols=False)
229
229
  where = query.build_where(self.condition)
230
- compiler = query.get_compiler(connection=schema_editor.connection)
230
+ compiler = query.get_compiler()
231
231
  sql, params = where.as_sql(compiler, schema_editor.connection)
232
232
  return sql % tuple(schema_editor.quote_value(p) for p in params)
233
233
 
@@ -347,8 +347,8 @@ class UniqueConstraint(BaseConstraint):
347
347
  kwargs["opclasses"] = self.opclasses
348
348
  return path, self.expressions, kwargs
349
349
 
350
- def validate(self, model, instance, exclude=None, using=DEFAULT_DB_ALIAS):
351
- queryset = model._default_manager.using(using)
350
+ def validate(self, model, instance, exclude=None):
351
+ queryset = model._default_manager
352
352
  if self.fields:
353
353
  lookup_kwargs = {}
354
354
  for field_name in self.fields:
@@ -358,7 +358,7 @@ class UniqueConstraint(BaseConstraint):
358
358
  lookup_value = getattr(instance, field.attname)
359
359
  if lookup_value is None or (
360
360
  lookup_value == ""
361
- and connections[using].features.interprets_empty_strings_as_nulls
361
+ and db_connection.features.interprets_empty_strings_as_nulls
362
362
  ):
363
363
  # A composite constraint containing NULL value cannot cause
364
364
  # a violation since NULL != NULL in SQL.
@@ -410,7 +410,7 @@ class UniqueConstraint(BaseConstraint):
410
410
  against = instance._get_field_value_map(meta=model._meta, exclude=exclude)
411
411
  try:
412
412
  if (self.condition & Exists(queryset.filter(self.condition))).check(
413
- against, using=using
413
+ against
414
414
  ):
415
415
  raise ValidationError(
416
416
  self.get_violation_error_message(),
plain/models/db.py CHANGED
@@ -1,10 +1,6 @@
1
1
  from plain import signals
2
2
 
3
- from .connections import (
4
- DEFAULT_DB_ALIAS,
5
- ConnectionHandler,
6
- ConnectionRouter,
7
- )
3
+ from .connections import DatabaseConnection
8
4
  from .exceptions import (
9
5
  ConnectionDoesNotExist,
10
6
  DatabaseError,
@@ -22,15 +18,13 @@ from .exceptions import (
22
18
  PLAIN_VERSION_PICKLE_KEY = "_plain_version"
23
19
 
24
20
 
25
- connections = ConnectionHandler()
26
-
27
- router = ConnectionRouter()
21
+ db_connection = DatabaseConnection()
28
22
 
29
23
 
30
24
  # Register an event to reset saved queries when a Plain request is started.
31
25
  def reset_queries(**kwargs):
32
- for conn in connections.all(initialized_only=True):
33
- conn.queries_log.clear()
26
+ if db_connection.has_connection():
27
+ db_connection.queries_log.clear()
34
28
 
35
29
 
36
30
  signals.request_started.connect(reset_queries)
@@ -39,8 +33,8 @@ signals.request_started.connect(reset_queries)
39
33
  # Register an event to reset transaction state and close connections past
40
34
  # their lifetime.
41
35
  def close_old_connections(**kwargs):
42
- for conn in connections.all(initialized_only=True):
43
- conn.close_if_unusable_or_obsolete()
36
+ if db_connection.has_connection():
37
+ db_connection.close_if_unusable_or_obsolete()
44
38
 
45
39
 
46
40
  signals.request_started.connect(close_old_connections)
@@ -48,9 +42,7 @@ signals.request_finished.connect(close_old_connections)
48
42
 
49
43
 
50
44
  __all__ = [
51
- "connections",
52
- "router",
53
- "DEFAULT_DB_ALIAS",
45
+ "db_connection",
54
46
  "PLAIN_VERSION_PICKLE_KEY",
55
47
  "Error",
56
48
  "InterfaceError",
@@ -2,25 +2,18 @@ from os import environ
2
2
 
3
3
  from . import database_url
4
4
 
5
- # Make DATABASES a required setting
6
- DATABASES: dict
5
+ # Make DATABASE a required setting
6
+ DATABASE: dict
7
7
 
8
- # Automatically configure DATABASES if a DATABASE_URL was given in the environment
8
+ # Automatically configure DATABASE if a DATABASE_URL was given in the environment
9
9
  if "DATABASE_URL" in environ:
10
- DATABASES = {
11
- "default": database_url.parse_database_url(
12
- environ["DATABASE_URL"],
13
- # Enable persistent connections by default
14
- conn_max_age=int(environ.get("DATABASE_CONN_MAX_AGE", 600)),
15
- conn_health_checks=environ.get(
16
- "DATABASE_CONN_HEALTH_CHECKS", "true"
17
- ).lower()
18
- in [
19
- "true",
20
- "1",
21
- ],
22
- )
23
- }
24
-
25
- # Classes used to implement DB routing behavior.
26
- DATABASE_ROUTERS = []
10
+ DATABASE = database_url.parse_database_url(
11
+ environ["DATABASE_URL"],
12
+ # Enable persistent connections by default
13
+ conn_max_age=int(environ.get("DATABASE_CONN_MAX_AGE", 600)),
14
+ conn_health_checks=environ.get("DATABASE_CONN_HEALTH_CHECKS", "true").lower()
15
+ in [
16
+ "true",
17
+ "1",
18
+ ],
19
+ )