Я пишу модуль Python для приложения на основе Django, которое обращается к базе данных Oracle через cx_Oracle.Похоже, что в коде django есть ошибка, которая нарушает использование метода executemany cx_Oracle.Если я использую cx_Oracle с подключением, открытым строго через cx_Oracle, логика работает нормально.Используйте соединение через django, оно не срабатывает.
Поскольку django является требованием, я ищу обходной путь и должен понять, что пытается сделать утверждение (ниже), где оно терпит неудачу.Я понимаю, что «%» используется и как оператор по модулю, и для форматирования строки, как, по-видимому, и в этом случае.Но, несмотря на большой поиск, кажется, что он не соответствует ни одному синтаксису форматирования строки с использованием "%", который я могу найти.Может кто-нибудь объяснить, что это пытается сделать?
query = query % tuple(args)
TypeError: not all arguments converted during string formatting
Где:
query = 'INSERT INTO DATABASE.TABLE\n (DATE, ID, COL_A, COL_B, COL_C)\n VALUES (:1, :2, :3, :4, :5)\n'
args = [':arg0', ':arg1', ':arg2', ':arg3', ':arg4']
Если вы введете эти значения и приведенный выше оператор в REPL, вы получите такую же ошибку.
Я знаю, что должен представить отчет об ошибке в Django.Разберусь с этим позже.На данный момент я надеюсь, что смогу как-то изменить позиционную нотацию Oracle bind-variable в строке запроса, чтобы удовлетворить приведенному выше выражениюОпять же, строка запроса без проблем работает напрямую с cx_Oracle.
Подробности:
Python 3.6.5 :: Anaconda, Inc.
cx-Oracle 7.0.0
Django 2.0.7
Формат запроса cx_Oracle: https://www.oracle.com/technetwork/articles/dsl/prez-python-queries-101587.html (см. «Много сразу»)
Мой код cx_Oracle:
cursor = conn.cursor()
cursor.prepare(query)
cursor.executemany(query, list_of_tuples_of_values)
rows_affected = cursor.rowcount
conn.commit()
Неисправный код находится в модуле django base.py, строка 494: (C: \ python \ Anaconda2 \ envs \ py36 \ lib \ site-packages \ django \ db \ backends \ oracle \ base.py)
def _fix_for_params(self, query, params, unify_by_values=False):
# cx_Oracle wants no trailing ';' for SQL statements. For PL/SQL, it
# it does want a trailing ';' but not a trailing '/'. However, these
# characters must be included in the original query in case the query
# is being passed to SQL*Plus.
if query.endswith(';') or query.endswith('/'):
query = query[:-1]
if params is None:
params = []
elif hasattr(params, 'keys'):
# Handle params as dict
args = {k: ":%s" % k for k in params}
query = query % args
elif unify_by_values and len(params) > 0:
# Handle params as a dict with unified query parameters by their
# values. It can be used only in single query execute() because
# executemany() shares the formatted query with each of the params
# list. e.g. for input params = [0.75, 2, 0.75, 'sth', 0.75]
# params_dict = {0.75: ':arg0', 2: ':arg1', 'sth': ':arg2'}
# args = [':arg0', ':arg1', ':arg0', ':arg2', ':arg0']
# params = {':arg0': 0.75, ':arg1': 2, ':arg2': 'sth'}
params_dict = {param: ':arg%d' % i for i, param in enumerate(set(params))}
args = [params_dict[param] for param in params]
params = {value: key for key, value in params_dict.items()}
query = query % tuple(args)
else:
# Handle params as sequence
args = [(':arg%d' % i) for i in range(len(params))]
query = query % tuple(args) <==============
return query, self._format_params(params)
params = (datetime.datetime(2018, 10, 12, 0, 0), '123456', 10, 10, 8)