1

この投稿の長さについて、事前にお詫び申し上げます。情報を漏らさないようにしたいだけです。

Django アプリの外部で Django の ORM を使用するアプリケーションがあり、call_command('syncdb')直接呼び出して「syncdb」を使用します (注: 以下にリストされているすべてのシナリオで virtualenv を使用しています)。

アプリケーションの単体テストでは、バックエンドとして SQLite を使用して「テスト」django データベースをセットアップしようとします (実稼働環境では MySQL を使用します)。

単体テストの 1 つが実行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変数は壊れた環境の狂ったように見えるクラッドのリストであるため、そのメソッドは各モデルのテーブル名がデータベースにないと誤​​って主張しているように見えます。これにより、最初に述べた元のエラーが表示されます。

本当に気が狂っていないことを確認するために、正しいリストを手動で挿入して比較してみました。

(動作しない環境)

(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'

編集: OK、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

どうやら、私の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 に答える
0

テキスト エディターは、ファイルを UTF-16LE として保存することを決定しました。ソースファイルの先頭、シバンの下に次を配置します。

# -*- coding: utf-16le -*-
于 2012-10-10T18:57:17.340 に答える