1

我要提前为这篇文章的长度道歉。我只是想确保我没有遗漏任何信息。

我有一个在 django 应用程序之外使用 django 的 ORM 的应用程序,它通过call_command('syncdb')直接调用使用“syncdb”(注意:我对下面列出的每个场景都使用了 virtualenv)。

我在应用程序中的单元测试尝试使用 SQLite 作为后端设置一个“测试”django 数据库(而生产环境使用 MySQL)。

每次运行一个单元测试时,它都会call_command('syncdb')在每个测试中使用相同的测试 django 设置进行调用。

我能够在 2 个不同的环境(一个使用 Windows 7/Python 2.7.3,另一个使用 Mac OS X ML/Python 2.7.2)上运行这些单元测试。测试完全没有问题;但这些都是相对干净的 Python 安装。

但是,当我尝试在 RHEL 服务器上运行它时,当单元测试尝试运行 syncdb 时,我收到以下错误:

DatabaseError:表“my_app_mytable”已经存在

经过大量令人沮丧的谷歌搜索和调试后,我(认为)我已经消除了此处此处报告的错误。

我做了很多修改,我想我已经将问题缩小到django 的 syncdb 命令文件中的这个语句(听起来很疯狂)(第 59 行):

tables = connection.introspection.table_names()

pdb.set_trace()在两个环境中都设置了一个内部 django 的 syncdb 源来查看。这是我发现的:

(有效的环境)

(Pdb) tables
[u'my_app_mytable', u'my_app_myothertable']

那里似乎还可以。从 syncdb 文件的外观来看,django 使用该tables变量来检查应用程序的模型与数据库中已有的模型。

(环境不起作用)

(Pdb) tables
[u'm\x00y\x00_\x00a\x00p\x00p\x00_\x00m\x00y\x00t\x00a\x00', u'm\x00y\x00_\x00a\x00p\x00p\x00_\x00m\x00y\x00o\x00t\x00']

除非我快疯了,否则我认为这会使 django 源代码中的以下语句返回 false:

def model_installed(model):
        opts = model._meta
        converter = connection.introspection.table_name_converter
        return not ((converter(opts.db_table) in tables) or
            (opts.auto_created and converter(opts.auto_created._meta.db_table) in tables))

该方法filter在该定义之后通过几行调用,看起来它检查是否converter(opts.db_table)tables列表中。我也在两种环境中手动运行它们:

(有效的环境)

(Pdb) opts = all_models[0][1][0]._meta
(Pdb) converter = connection.introspection.table_name_converter
(Pdb) converter(opts.db_table) in tables
True

如您所见,我(有点)手动运行该model_installed函数以查看converter(opts.db_table)返回的内容,并且在两种环境中它看起来都像是一个完全正常的字符串。然而:

(环境不起作用)

(Pdb) opts = all_models[0][1][0]._meta
(Pdb) converter = connection.introspection.table_name_converter
(Pdb) converter(opts.db_table) in tables
False

因此,看起来由于tables变量是损坏环境中看起来很疯狂的 crud 列表,因此该方法错误地声称每个模型的表名不在数据库中,这给了我在开始时所说的原始错误。

为了确保我真的没有发疯,我还尝试手动插入正确的列表进行比较:

(环境不起作用)

(Pdb) converter(opts.db_table) in [u'my_app_mytable', u'my_app_myothertable']
True

我需要在这个环境中重新编译 Python 吗?我在 stackoverflow 上阅读了以下问题,发现我破碎的环境表现出奇怪的行为:

(myvirtualenv)[username@myserver]$ python
Python 2.7.3 (default, Apr 12 2012, 10:40:11)
[GCC 4.4.6 20110731 (Red Hat 4.4.6-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import StringIO, cStringIO, sys
>>> StringIO.StringIO(u"fubar").getvalue()
u'fubar'
>>> cStringIO.StringIO(u"fubar").getvalue()
'fubar'
>>> cStringIO.StringIO(u"\u0405\u0406").getvalue()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
>>> sys.maxunicode
65535
>>> sys.byteorder
'little'

编辑:好的,所以我稍微浏览了 django 源代码,看起来他们正在以这种方式获取表格列表:

def get_table_list(self, cursor):
    "Returns a list of table names in the current database."
    # Skip the sqlite_sequence system table used for autoincrement key
    # generation.
    cursor.execute("""
        SELECT name FROM sqlite_master
        WHERE type='table' AND NOT name='sqlite_sequence'
        ORDER BY name""")
    return [row[0] for row in cursor.fetchall()]

所以我在 python 解释器中手动连接到 sqlite 文件,并运行该查询:

(环境不起作用)

>>> import sqlite3
>>> conn = sqlite3.connect('/path/to/sqlite/file')
>>> curs = conn.cursor()
>>> curs.execute("""
... SELECT name FROM sqlite_master
... WHERE type='table' AND NOT name='sqlite_sequence'
... ORDER BY name""")
<sqlite3.Cursor object at 0xb7557500>
>>> curs.fetchall()
[(u'c\x00c\x00_\x00s\x00t\x00a\x00t\x00s\x00_\x00c\x00c\x00',), (u'c\x00c\x00_\x00s\x00t\x00a\x00t\x00s\x00_\x00c\x00c\x00s',)]

所以看起来 SQLite 为该查询返回了一个 UTF16-LE 字符串。在工作环境上,它返回以下内容:

(有效的环境)

>>> curs.fetchall()
[(u'my_app_mytable',), (u'my_app_myothertable',)]

models即使没有在顶部定义编码,“工作”环境在解释我的文件和适当地创建表时似乎也没有任何问题。是否有一些 SQLite 默认设置导致了这种情况?还是 git 在损坏的环境中将文件转换为 UTF-16LE,并在工作环境中坚持使用 UTF-8/ASCII?

4

3 回答 3

2

我遇到了类似的问题,相同的 syncdb 命令在一个环境中成功执行,而不是在具有相同数据库导入和模型的其他环境中成功执行。更改call_command(syncdb)os.system('python ' + |path|, 'manage.py syncdb'))我解决了它。

希望它可以帮助别人。

于 2013-12-20T05:10:47.463 回答
0

您的文本编辑器已决定将文件保存为 UTF-16LE。将以下内容放在源文件的顶部,shebang 下方:

# -*- coding: utf-16le -*-
于 2012-10-10T18:57:17.340 回答
0

好吧,看来我的sqlite3模块正在运行。我最终重新安装了 Red Hat 的sqlite-devel软件包,重新编译了 Python 2.7.3,然后更新了 virtualenv 中的可执行文件。

似乎现在运作良好。现在,当我运行 django 的get_table_list()查询时,我得到以下信息:

>>> import sqlite3
>>> conn = sqlite3.connect('/path/to/sqlite/file')
>>> curs = conn.cursor()
>>> curs.execute("""
... SELECT name FROM sqlite_master
... WHERE type='table' AND NOT name='sqlite_sequence'
... ORDER BY name""")
<sqlite3.Cursor object at 0xb7774ca0>
>>> curs.fetchall()
[(u'my_app_mytable',), (u'my_app_myothertable',)]

我没有对 sqlite 文件本身进行任何更改,所以这似乎是sqlite3模块和/或我的 Python 2.7.3 安装的问题。

于 2012-10-11T02:22:16.583 回答