When running Django v5.2.7 with oracledb 3.4.0, the following traceback is generated. In the 3.4.0 release they changed the definition of Binary from an alias to bytes to a function (https://github.com/oracle/python-oracledb/blob/a71468238ea98f38a331afe0a0664b2fa707a294/src/oracledb/constructors.py#L37-L41). The issue does not occur with oracledb 3.3.0.
Traceback (most recent call last):
File "C:\Users\johnwa\AppData\Roaming\uv\python\cpython-3.13.7-windows-x86_64-none\Lib\threading.py", line 1043, in _bootstrap_inner
self.run()
~~~~~~~~^^
File "C:\Users\johnwa\AppData\Roaming\uv\python\cpython-3.13.7-windows-x86_64-none\Lib\threading.py", line 994, in run
self._target(*self._args, **self._kwargs)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\utils\autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
~~^^^^^^^^^^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\core\management\commands\runserver.py", line 137, in inner_run
self.check_migrations()
~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\core\management\base.py", line 587, in check_migrations
executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\migrations\executor.py", line 18, in __init__
self.loader = MigrationLoader(self.connection)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\migrations\loader.py", line 58, in __init__
self.build_graph()
~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\migrations\loader.py", line 235, in build_graph
self.applied_migrations = recorder.applied_migrations()
~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\migrations\recorder.py", line 89, in applied_migrations
if self.has_table():
~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\migrations\recorder.py", line 63, in has_table
with self.connection.cursor() as cursor:
~~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\utils\asyncio.py", line 26, in inner
return func(*args, **kwargs)
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\backends\base\base.py", line 320, in cursor
return self._cursor()
~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\backends\base\base.py", line 296, in _cursor
self.ensure_connection()
~~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\utils\asyncio.py", line 26, in inner
return func(*args, **kwargs)
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\backends\base\base.py", line 279, in ensure_connection
self.connect()
~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\utils\asyncio.py", line 26, in inner
return func(*args, **kwargs)
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\backends\base\base.py", line 258, in connect
self.init_connection_state()
~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\backends\oracle\base.py", line 336, in init_connection_state
cursor.execute(
~~~~~~~~~~~~~~^
"SELECT 1 FROM DUAL WHERE DUMMY %s"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
% self._standard_operators["contains"],
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
["X"],
^^^^^^
)
^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\backends\oracle\base.py", line 630, in execute
query, params = self._fix_for_params(query, params, unify_by_values=True)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\backends\oracle\base.py", line 627, in _fix_for_params
return query, self._format_params(params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\backends\oracle\base.py", line 555, in _format_params
return {k: OracleParam(v, self, True) for k, v in params.items()}
~~~~~~~~~~~^^^^^^^^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\db\backends\oracle\base.py", line 441, in __init__
elif isinstance(param, (Database.Binary, datetime.timedelta)):
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union
Thank you John Wagenleitner, do you have availability to work on the fix? It seems that our
Database.DateandDatabase.Timestampmay also be affected?Setting as "New Feature" since oracledb 3.4.0 was released October 2025.
For reference, commit 869a887819cdac7fcd610f9d9d463ade49ea7de6 contains:
src/oracledb/constructors.py
# synonyms for the types mandated by the database APIBinary = bytesDate = datetime.dateTimestamp = datetime.datetimeerrors._raise_err(errors.ERR_TIME_NOT_SUPPORTED)