base_impl.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import importlib
  2. from django.conf import settings
  3. from django.core.exceptions import ImproperlyConfigured
  4. from django.db import DEFAULT_DB_ALIAS, connections
  5. from django.db.backends.postgresql.base import DatabaseWrapper
  6. from django.db.backends.postgresql.introspection import ( # type: ignore[import]
  7. DatabaseIntrospection,
  8. )
  9. from django.db.backends.postgresql.operations import DatabaseOperations
  10. from django.db.backends.postgresql.schema import ( # type: ignore[import]
  11. DatabaseSchemaEditor,
  12. )
  13. from django.db.backends.postgresql.base import ( # isort:skip
  14. DatabaseWrapper as Psycopg2DatabaseWrapper,
  15. )
  16. def base_backend_instance():
  17. """Gets an instance of the base class for the custom database back-end.
  18. This should be the Django PostgreSQL back-end. However,
  19. some people are already using a custom back-end from
  20. another package. We are nice people and expose an option
  21. that allows them to configure the back-end we base upon.
  22. As long as the specified base eventually also has
  23. the PostgreSQL back-end as a base, then everything should
  24. work as intended.
  25. We create an instance to inspect what classes to subclass
  26. because not all back-ends set properties such as `ops_class`
  27. properly. The PostGIS back-end is a good example.
  28. """
  29. base_class_name = getattr(
  30. settings,
  31. "POSTGRES_EXTRA_DB_BACKEND_BASE",
  32. "django.db.backends.postgresql",
  33. )
  34. base_class_module = importlib.import_module(base_class_name + ".base")
  35. base_class = getattr(base_class_module, "DatabaseWrapper", None)
  36. if not base_class:
  37. raise ImproperlyConfigured(
  38. (
  39. "'%s' is not a valid database back-end."
  40. " The module does not define a DatabaseWrapper class."
  41. " Check the value of POSTGRES_EXTRA_DB_BACKEND_BASE."
  42. )
  43. % base_class_name
  44. )
  45. if isinstance(base_class, Psycopg2DatabaseWrapper):
  46. raise ImproperlyConfigured(
  47. (
  48. "'%s' is not a valid database back-end."
  49. " It does inherit from the PostgreSQL back-end."
  50. " Check the value of POSTGRES_EXTRA_DB_BACKEND_BASE."
  51. )
  52. % base_class_name
  53. )
  54. base_instance = base_class(connections.databases[DEFAULT_DB_ALIAS])
  55. if base_instance.connection:
  56. raise ImproperlyConfigured(
  57. (
  58. "'%s' establishes a connection during initialization."
  59. " This is not expected and can lead to more connections"
  60. " being established than neccesarry."
  61. )
  62. % base_class_name
  63. )
  64. return base_instance
  65. def backend() -> DatabaseWrapper:
  66. """Gets the base class for the database back-end."""
  67. return base_backend_instance().__class__
  68. def schema_editor() -> DatabaseSchemaEditor:
  69. """Gets the base class for the schema editor.
  70. We have to use the configured base back-end's schema editor for
  71. this.
  72. """
  73. return base_backend_instance().SchemaEditorClass
  74. def introspection() -> DatabaseIntrospection:
  75. """Gets the base class for the introspection class.
  76. We have to use the configured base back-end's introspection class
  77. for this.
  78. """
  79. return base_backend_instance().introspection.__class__
  80. def operations() -> DatabaseOperations:
  81. """Gets the base class for the operations class.
  82. We have to use the configured base back-end's operations class for
  83. this.
  84. """
  85. return base_backend_instance().ops.__class__