# Buggy code
def install_sql_hook():
    # type: () -> None
    """If installed this causes Django's queries to be captured."""
    try:
        from django.db.backends.utils import CursorWrapper  # type: ignore
    except ImportError:
        from django.db.backends.util import CursorWrapper  # type: ignore

    try:
        real_execute = CursorWrapper.execute
        real_executemany = CursorWrapper.executemany
    except AttributeError:
        # This won't work on Django versions < 1.6
        return

    def record_many_sql(sql, param_list):
        for params in param_list:
            record_sql(sql, params)

    def execute(self, sql, params=None):
        try:
            return real_execute(self, sql, params)
        finally:
            record_sql(sql, params)

    def executemany(self, sql, param_list):
        try:
            return real_executemany(self, sql, param_list)
        finally:
            record_many_sql(sql, param_list)

    CursorWrapper.execute = execute
    CursorWrapper.executemany = executemany
    ignore_logger("django.db.backends")


# Traceback (TypeError)
$ ./manage.py test-sentry
Traceback (most recent call last):
File "./manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 375, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.6/site-packages/django/core/management/base.py", line 316, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.6/site-packages/django/core/management/base.py", line 353, in execute
output = self.handle(*args, **options)
File "/ph/ph/app/management/commands/test-sentry.py", line 18, in handle
'foo': 'foo',
File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
return super().execute(sql, params)
File "/usr/local/lib/python3.6/site-packages/sentry_sdk/integrations/django/__init__.py", line 273, in execute
record_sql(sql, params)
File "/usr/local/lib/python3.6/site-packages/sentry_sdk/integrations/django/__init__.py", line 240, in record_sql
real_sql, real_params = format_sql(sql, params)
File "/usr/local/lib/python3.6/site-packages/sentry_sdk/integrations/django/__init__.py", line 222, in format_sql
sql = sql % conv
TypeError: unsupported operand type(s) for %: 'Composed' and '_FormatConverter'
$

# Fixed code
def install_sql_hook():
    # type: () -> None
    """If installed this causes Django's queries to be captured."""
    try:
        from django.db.backends.utils import CursorWrapper  # type: ignore
    except ImportError:
        from django.db.backends.util import CursorWrapper  # type: ignore

    try:
        real_execute = CursorWrapper.execute
        real_executemany = CursorWrapper.executemany
    except AttributeError:
        # This won't work on Django versions < 1.6
        return

    def record_many_sql(sql, param_list, cursor):
        for params in param_list:
            record_sql(sql, params, cursor)

    def execute(self, sql, params=None):
        try:
            return real_execute(self, sql, params)
        finally:
            record_sql(sql, params, self.cursor)

    def executemany(self, sql, param_list):
        try:
            return real_executemany(self, sql, param_list)
        finally:
            record_many_sql(sql, param_list, self.cursor)

    CursorWrapper.execute = execute
    CursorWrapper.executemany = executemany
    ignore_logger("django.db.backends")