apps.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. from django.apps import AppConfig
  2. from django.core.signals import setting_changed
  3. from django.db import connections
  4. from django.db.backends.postgresql.psycopg_any import RANGE_TYPES
  5. from django.db.backends.signals import connection_created
  6. from django.db.migrations.writer import MigrationWriter
  7. from django.db.models import CharField, OrderBy, TextField
  8. from django.db.models.functions import Collate
  9. from django.db.models.indexes import IndexExpression
  10. from django.utils.translation import gettext_lazy as _
  11. from .indexes import OpClass
  12. from .lookups import (
  13. SearchLookup,
  14. TrigramSimilar,
  15. TrigramStrictWordSimilar,
  16. TrigramWordSimilar,
  17. Unaccent,
  18. )
  19. from .serializers import RangeSerializer
  20. from .signals import register_type_handlers
  21. def uninstall_if_needed(setting, value, enter, **kwargs):
  22. """
  23. Undo the effects of PostgresConfig.ready() when django.contrib.postgres
  24. is "uninstalled" by override_settings().
  25. """
  26. if (
  27. not enter
  28. and setting == "INSTALLED_APPS"
  29. and "django.contrib.postgres" not in set(value)
  30. ):
  31. connection_created.disconnect(register_type_handlers)
  32. CharField._unregister_lookup(Unaccent)
  33. TextField._unregister_lookup(Unaccent)
  34. CharField._unregister_lookup(SearchLookup)
  35. TextField._unregister_lookup(SearchLookup)
  36. CharField._unregister_lookup(TrigramSimilar)
  37. TextField._unregister_lookup(TrigramSimilar)
  38. CharField._unregister_lookup(TrigramWordSimilar)
  39. TextField._unregister_lookup(TrigramWordSimilar)
  40. CharField._unregister_lookup(TrigramStrictWordSimilar)
  41. TextField._unregister_lookup(TrigramStrictWordSimilar)
  42. # Disconnect this receiver until the next time this app is installed
  43. # and ready() connects it again to prevent unnecessary processing on
  44. # each setting change.
  45. setting_changed.disconnect(uninstall_if_needed)
  46. MigrationWriter.unregister_serializer(RANGE_TYPES)
  47. class PostgresConfig(AppConfig):
  48. name = "django.contrib.postgres"
  49. verbose_name = _("PostgreSQL extensions")
  50. def ready(self):
  51. setting_changed.connect(uninstall_if_needed)
  52. # Connections may already exist before we are called.
  53. for conn in connections.all(initialized_only=True):
  54. if conn.vendor == "postgresql":
  55. conn.introspection.data_types_reverse.update(
  56. {
  57. 3904: "django.contrib.postgres.fields.IntegerRangeField",
  58. 3906: "django.contrib.postgres.fields.DecimalRangeField",
  59. 3910: "django.contrib.postgres.fields.DateTimeRangeField",
  60. 3912: "django.contrib.postgres.fields.DateRangeField",
  61. 3926: "django.contrib.postgres.fields.BigIntegerRangeField",
  62. }
  63. )
  64. if conn.connection is not None:
  65. register_type_handlers(conn)
  66. connection_created.connect(register_type_handlers)
  67. CharField.register_lookup(Unaccent)
  68. TextField.register_lookup(Unaccent)
  69. CharField.register_lookup(SearchLookup)
  70. TextField.register_lookup(SearchLookup)
  71. CharField.register_lookup(TrigramSimilar)
  72. TextField.register_lookup(TrigramSimilar)
  73. CharField.register_lookup(TrigramWordSimilar)
  74. TextField.register_lookup(TrigramWordSimilar)
  75. CharField.register_lookup(TrigramStrictWordSimilar)
  76. TextField.register_lookup(TrigramStrictWordSimilar)
  77. MigrationWriter.register_serializer(RANGE_TYPES, RangeSerializer)
  78. IndexExpression.register_wrappers(OrderBy, OpClass, Collate)