【问题标题】:Can't query SQL Server from django using django-pyodbc无法使用 django-pyodbc 从 django 查询 SQL Server
【发布时间】:2014-01-22 02:13:00
【问题描述】:

我正在尝试使用manage.py syncdb 将在 IIS 7 上远程运行的 SQL Server 2008 R2 数据库同步到在 Windows 7 上运行 python 3.3 的 django 1.6 应用程序。但是我遇到了错误,

TypeError: The first argument to execute must be a string or unicode query.

我安装了 django-pyodbc 0.2.3 和 pyodbc 3.0.7,我的 settings.py DATABASES 为,

{
  'default': {
    'ENGINE': 'django_pyodbc',
    'HOST': '...',
    'NAME': '...',
    'OPTIONS': {
      'host_is_server': True
    }
  }
}

您可能猜到了,USERPASSWORD 被省略了,因为我需要 Integrated_Security=YesTrusted_Connection=Yes 进行连接。由于 django-pyodbc 初始化类 DatabaseWrapper 的方式,OPTIONS 似乎必须为非空,即使 host_is_server 在 Windows 上无关。

我收到的完整错误是:

Traceback (most recent call last):
  File "Z:\python\ns_reports_server\manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "C:\Python33\lib\site-packages\django-1.6.1-py3.3.egg\django\core\management\__init__.py", line 399, in execute_from_command_line
    utility.execute()
  File "C:\Python33\lib\site-packages\django-1.6.1-py3.3.egg\django\core\management\__init__.py", line 392, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Python33\lib\site-packages\django-1.6.1-py3.3.egg\django\core\management\base.py", line 242, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "C:\Python33\lib\site-packages\django-1.6.1-py3.3.egg\django\core\management\base.py", line 285, in execute
    output = self.handle(*args, **options)
  File "C:\Python33\lib\site-packages\django-1.6.1-py3.3.egg\django\core\management\base.py", line 415, in handle
    return self.handle_noargs(**options)
  File "C:\Python33\lib\site-packages\django-1.6.1-py3.3.egg\django\core\management\commands\syncdb.py", line 57, in handle_noargs
    cursor = connection.cursor()
  File "C:\Python33\lib\site-packages\django-1.6.1-py3.3.egg\django\db\backends\__init__.py", line 157, in cursor
    cursor = self.make_debug_cursor(self._cursor())
  File "C:\Python33\lib\site-packages\django_pyodbc-0.2.3-py3.3.egg\django_pyodbc\base.py", line 290, in _cursor
  File "C:\Python33\lib\site-packages\django_pyodbc-0.2.3-py3.3.egg\django_pyodbc\operations.py", line 31, in _get_sql_server_ver
  File "C:\Python33\lib\site-packages\django-1.6.1-py3.3.egg\django\db\backends\util.py", line 69, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "C:\Python33\lib\site-packages\django-1.6.1-py3.3.egg\django\db\backends\util.py", line 51, in execute
    return self.cursor.execute(sql)
  File "C:\Python33\lib\site-packages\django_pyodbc-0.2.3-py3.3.egg\django_pyodbc\base.py", line 410, in execute
TypeError: The first argument to execute must be a string or unicode query.

如果您查看从顶部开始第十次调用的源代码,django_pyodbc/operations.py 正在查询 SQL Server 版本的连接,

cur.execute("SELECT CAST(SERVERPROPERTY('ProductVersion') as varchar)")

然而,到了调用栈的末尾,这个要执行的sql已经消失了。 django_pyodbc/base.py有,

return self.cursor.execute(sql, params)

第一个参数未被识别为“字符串或 unicode 查询”。

Python、django 和 SQL Server 对我来说都是新的,所以答案可能很明显,但我一辈子都无法解决。干杯。

【问题讨论】:

    标签: python sql-server django django-pyodbc


    【解决方案1】:

    编辑:driver_supports_utf8=True 其他答案中提到的将是正确的解决方法。

    看起来这是 django-pyodbc 和 Python 3 的问题。

    在base.py中,第367行是

    sql = sql.encode('utf-8')
    

    这一行将字符串转换为导致 TypeError 的字节。就像你一样 在 Windows 上,我假设驱动程序可以处理 unicode。我建议您注释掉第 364 到 367 行(format_sql 函数中的前 4 行)。这样,您的 unicode 字符串将保持 unicode,并且您不会收到 TypeError。

    https://github.com/lionheart/django-pyodbc/blob/master/django_pyodbc/base.py

    def format_sql(self, sql, n_params=None):
        if not self.driver_supports_utf8 and isinstance(sql, text_type):
            # Older FreeTDS (and other ODBC drivers?) don't support Unicode yet, so
            # we need to encode the SQL clause itself in utf-8
            sql = sql.encode('utf-8')
        # pyodbc uses '?' instead of '%s' as parameter placeholder.
        if n_params is not None:
            try:
                sql = sql % tuple('?' * n_params)
            except:
                #Todo checkout whats happening here
                pass
        else:
            if '%s' in sql:
                sql = sql.replace('%s', '?')
        return sql
    

    我提出了一个关于 django-pyodbc 的问题,该问题更详细。

    https://github.com/lionheart/django-pyodbc/issues/47

    【讨论】:

      【解决方案2】:

      您也可以在配置选项中解决此问题。我和这个斗争了一段时间。尝试将您的数据库更改为 1.6 的配置:

      DATABASES = {
          'default': {
              'ENGINE': 'django_pyodbc',
              'NAME': 'db_name',
              'USER': 'db_user',
              'PASSWORD': 'your_password',            
              'HOST': 'database.domain.com,1433',
              'PORT': '1433',
              'OPTIONS': {
                  'host_is_server': True,
                  'autocommit': True,
                  'unicode_results': True,
                  'extra_params': 'tds_version=8.0'
              },
          }
      }
      

      如果您在 Windows 上,“extra_params”会被忽略,但它可以移植到 Linux。

      【讨论】:

      • 关键部分是“自动提交”:是的,对于这个问题(从 Django 1.6 开始),但如果您使用的是 Python 3.x,则 unicode_results 行也是必要的。此外,自从这个答案以来,我学到了很多东西——虽然当时 8.0 被广泛报道为正确的(并且仍然有效),但在 FreeTDS 下,tds_version 实际上应该是 7.2。
      【解决方案3】:

      通过添加'driver_supports_utf8': True,'为我们解决了这个问题

      'characteristics': {
          'ENGINE': "django_pyodbc",
          'HOST': "ourdbhost.com",
          'PORT': 5555,
          'NAME': "OurDB",
          'USER': "ouruser",
          'PASSWORD': "acoolpw",
          'OPTIONS': {
              'driver_supports_utf8': True,
              'host_is_server': True,
              'extra_params': 'TDS_Version=7.1',
          },
      },
      

      按照 gri 在https://github.com/lionheart/django-pyodbc/issues/47 上的建议工作

      添加

              'autocommit': True,
              'unicode_results': True,
      

      OPTIONS 没有修复它,但也没有破坏任何东西

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-04-08
        • 2021-06-15
        • 2019-05-20
        • 1970-01-01
        • 2017-08-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多