Проблема Psycopg2 не может адаптировать тип 'tuple', возникающая периодически

Недавно мы обновили Django & Python до следующей версии

Python 3.9.5, Django 3.2, Psycopg2 2.9.1, Httpd 2,4.2, Postgres 12.8

Заметили, что приложение периодически выходило из строя с ошибкой psycopg2.ProgrammingError: can't adapt type 'tuple'

Ниже приведены запрос и параметры, зарегистрированные перед выполнением cursor.execute()

{'employer_id': 200176, 'approximate_age_band': ('30-39', '50-59')

SELECT month_key as cadence_val, sum(eligible_count) as eligible
    FROM xyz_table_name 
    WHERE employer_id = %(employer_id)s      
    AND approximate_age_band IN %(approximate_age_band)s GROUP BY 1 ORDER BY 1;

Ниже приведена полная трассировка стека

2021-10-27 05:00:52,280 [ERROR] django.request: Internal Server Error: mobile_report/reports
Traceback (most recent call last):
  File "/var/www/pulse_preprod/service/venv/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: can't adapt type 'tuple'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/var/www/service_rest/service/api/views.py", line 375, in mobile_visits
    data = get_report_data(request, "VisitsReport", src_employer_id)
  File "/var/www/service_rest/service/api/views.py", line 453, in get_report_data
    data = get_data(src_employer_id, filter_params, report_key, **params)
  File "/var/www/service_rest/service/api/views.py", line 466, in get_data
    data = report_obj.get_data(employer, filter_values, **params)
  File "/var/www/service_rest/service/reports/pulse/mobile.py", line 49, in get_data
    rows1, cadence_list = self.get_rows_from_query(cursor, sql1, employer_id, table_name,
  File "/var/www/service_rest/service/reports/__init__.py", line 1415, in get_rows_from_query
    cursor.execute(sql, params)
  File "/var/www/pulse_preprod/service/venv/lib/python3.9/site-packages/django/db/backends/utils.py", line 66, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/var/www/pulse_preprod/service/venv/lib/python3.9/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/var/www/pulse_preprod/service/venv/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/var/www/pulse_preprod/service/venv/lib/python3.9/site-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/var/www/pulse_preprod/service/venv/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
django.db.utils.Error: can't adapt type 'tuple'

Во время нескольких попыток запрос работает нормально несколько раз (возвращая ожидаемые данные из БД), но случайным образом выдает эту ошибку.

Это вроде как исключает зависимость от python или расширение psycopg2 или проблемы с данными БД, верно?

Любая помощь будет принята с благодарностью.

Самым простым исправлением будет использование approximate_age_band в качестве списка:

cur = connection.cursor()

values = {'employer_id': 200176, 'approximate_age_band': ['30-39', '50-59']}

query = """select *
from test t
where t.approximate_age_band = ANY(%(approximate_age_band)s)
"""
print(cur.mogrify(query, values).decode('utf-8')) # Show the executed SQL statement
cur.execute(query, values)
print(cur.fetchall())

Выход:

select *
from test t
where t.approximate_age_band = ANY(ARRAY['30-39','50-59'])
[
  (None, None, 420, 509, '50-59'), 
  (None, None, 210, 508, '30-39')
]
Вернуться на верх