9

私はこのコードを持っています:

try:
    parent_comment = models.Comment.all_objects.get(id=parent_comment_id)
except models.Comment.DoesNotExist:
    parent_comment = None

if parent_comment is not None and parent_comment_id is None:
    raise Exception("WTF django/mysql")

...そして時々、何らかの形で例外が発生します。どうしてこれが起こるのでしょうか?

ときどき、1 日に数回、一見ランダムな Comment インスタンスが返されます。通常は期待どおりに動作し、None を返します。

これは Comment テーブルの id フィールドです:id int(11) NOT NULL AUTO_INCREMENTしたがって、null 可能というわけではありません。InnoDB テーブルです。

Comment.all_objects に関しては、これがその定義です:all_objects = Manager()そしてそれはそのクラスの最初の行です。

Django 1.2.7 を使用しています。

更新 例外が発生したときに生成される SQL を取得するために、例外にログを追加しました。ここにあります:

SELECT `canvas_comment`.`id`, `canvas_comment`.`visibility`, `canvas_comment`.`parent_content_id`, `canvas_comment`.`parent_comment_id`, `canvas_comment`.`timestamp`, `canvas_comment`.`reply_content_id`, `canvas_comment`.`reply_text`, `canvas_comment`.`replied_comment_id`, `canvas_comment`.`category_id`, `canvas_comment`.`author_id`, `canvas_comment`.`title`, `canvas_comment`.`ip`, `canvas_comment`.`anonymous`, `canvas_comment`.`score`, `canvas_comment`.`judged`, `canvas_comment`.`ot_hidden` FROM `canvas_comment` WHERE `canvas_comment`.`id` IS NULL
4

2 に答える 2

13

この動作は、非常に奇妙な (このコーダーの謙虚な意見では) MySQL の動作によって引き起こされSQL_AUTO_IS_NULL変数によって制御されます(1デフォルトでは MySQL < 5.5.3 です)。

この変数が 1 に設定されている場合、自動生成された AUTO_INCREMENT 値を正常に挿入するステートメントの後で、次の形式のステートメントを発行することによってその値を見つけることができます。

SELECT * FROM tbl_name WHERE auto_col IS NULL

ステートメントが行を返す場合、返される値は、LAST_INSERT_ID() 関数を呼び出した場合と同じです。

この「機能」によって引き起こされる同様の混乱を説明する Django バグ (クローズ済み: 修正なし)があり、その中でコア開発者は次のように述べています。

その動作が望ましくない場合は、好みに合わせて正しいことを行うようにデータベースを構成する必要があります

解決策は、ステートメントを使用しSQL_AUTO_IS_NULLて MySQL データベースのオプションを無効にすることです。次のようなものでこれを行うことができます:SETsettings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        # ... your DB options
        'OPTIONS': {
            'init_command': 'SET SQL_AUTO_IS_NULL=0;'
        },
    }
}

長期的には、django-developers リストでドラムビートを試して、以前の立場を再考してもらうことができます。

幸いなことに、ここでの私の考えでは、橋を燃やしているわけではありません。誰かがそれをテストしたい場合、またはデフォルトで使用したい場合は、設定で DATABASE_OPTIONS を介してデータベース初期化オプションを使用できます...「read_default_file」と「init_command」の両方がそこで役立ちます。

これが「絶対にダメだ」と言っているわけではありませんが、今のところ、これを行う価値があるとは確信していません。それに対してバランスが取れているのは、それが起こる可能性があることを人々に知らせる方法です...肩をすくめる..最初に、databases.txtに何かを追加するかもしれません。私はこの種のバランスをとる行為が嫌いです。:-(

于 2012-08-10T19:37:22.140 に答える
1

単純なものを除外するには:

  1. コメントモデルを投稿していただけますか
  2. DBに対して次のクエリを実行できますか

SELECT COUNT(id) FROM <your_comment_table> WHERE id <= 0 OR id ='' OR id IS NULL

あなたのコードは論理的に、モデル コードのどこかがおかしくない限り機能するはずです。これは、データに関連しているに違いないと私に信じさせます。

編集

別のアイデアとして、django の ORM が何をクエリしているかを確認してください (これで何が起きているかがわかります):

parent_comment = models.Comment.all_objects.get(id=parent_comment_id)
raise Exception(parent_comment.query) # should display out the query thats being generated
于 2012-08-10T17:55:28.663 に答える