altairbow / django-db-connection-pool

Database connection pool component library for Django
https://pypi.python.org/pypi/django-db-connection-pool/
MIT License
181 stars 24 forks source link

Django 4.2 incompatibility #47

Closed joshorr closed 1 year ago

joshorr commented 1 year ago

Describe the bug

When upgrading to Django 4.2, I got an exception deep in Django where it tries to get the self.connection.server_version; which is an empty dict currently.

Where the self.connection is a <sqlalchemy.pool.base._ConnectionFairy> and if you do self.connection.connection.info.server_version it works fine!

The ConnectionFairy has an attribute name conflict as mentioned in this issue I found on sqlalchemy related to this, and a comment on that issue (https://github.com/sqlalchemy/sqlalchemy/issues/4620#issuecomment-485029542). Comment talks about simply assigning the .info to the .connection.info after establishing the connection to fix the problem.

If I do that (locally, with a cloned version of django-db-connection-pool), it seems to work. I could push up a PR for you to look at if you want.

Code that fixes issue (file: dj_db_conn_pool/backends/postgresql/base.py):

class DatabaseWrapper(PGDatabaseWrapperMixin, base.DatabaseWrapper):
    def get_new_connection(self, conn_params):
        connection = super().get_new_connection(conn_params)
        connection.info = connection.connection.info
        return connection

Exception:

AttributeError: 'dict' object has no attribute 'server_version'

Environment

Traceback

Traceback (most recent call last):
  File ".../site-packages/rest_framework/request.py", line 74, in wrap_attributeerrors
    yield
  File ".../site-packages/rest_framework/request.py", line 227, in user
    self._authenticate()
  File ".../site-packages/rest_framework/request.py", line 380, in _authenticate
    user_auth_tuple = authenticator.authenticate(self)
  File "auth.py", line 355, in authenticate
    user = User.objects.get(id=user_id)
  File ".../site-packages/django/db/models/manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File ".../site-packages/django/db/models/query.py", line 633, in get
    num = len(clone)
  File ".../site-packages/django/db/models/query.py", line 380, in __len__
    self._fetch_all()
  File ".../site-packages/django/db/models/query.py", line 1881, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File ".../site-packages/django/db/models/query.py", line 91, in __iter__
    results = compiler.execute_sql(
  File ".../site-packages/django/db/models/sql/compiler.py", line 1558, in execute_sql
    cursor = self.connection.cursor()
  File ".../site-packages/django/utils/asyncio.py", line 26, in inner
    return func(*args, **kwargs)
  File ".../site-packages/django/db/backends/base/base.py", line 330, in cursor
    return self._cursor()
  File ".../site-packages/django/db/backends/base/base.py", line 306, in _cursor
    self.ensure_connection()
  File ".../site-packages/django/utils/asyncio.py", line 26, in inner
    return func(*args, **kwargs)
  File ".../site-packages/django/db/backends/base/base.py", line 289, in ensure_connection
    self.connect()
  File ".../site-packages/django/utils/asyncio.py", line 26, in inner
    return func(*args, **kwargs)
  File ".../site-packages/django/db/backends/base/base.py", line 272, in connect
    self.init_connection_state()
  File ".../site-packages/django/db/backends/postgresql/base.py", line 309, in init_connection_state
    super().init_connection_state()
  File ".../site-packages/django/db/backends/base/base.py", line 239, in init_connection_state
    self.check_database_version_supported()
  File ".../site-packages/django/db/backends/base/base.py", line 210, in check_database_version_supported
    and self.get_database_version() < self.features.minimum_database_version
  File ".../site-packages/django/db/backends/postgresql/base.py", line 188, in get_database_version
    return divmod(self.pg_version, 10000)
  File ".../site-packages/django/utils/functional.py", line 57, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File ".../site-packages/django/db/backends/postgresql/base.py", line 437, in pg_version
    return self.connection.info.server_version
AttributeError: 'dict' object has no attribute 'server_version'
altairbow commented 1 year ago

Thanks for feedback, I changed the code based on your code, tested and works