2

問題:シグナル受信者が特定の条件に対してモデルエントリが存在するかどうかを確認し、存在しない場合は新しいエントリを作成します。まれに、エントリが重複しています。レシーバ関数内重複要求スレッドがDjangoモデルの重複したデータベースエントリを作成します

try: 
    my_instance = MyModel.objects.get(field1=value1, field2=sender) 
except: 
    my_instance = MyModel(field1=value1, field2=sender) 
    my_instance.save() 

それはget_or_createヘルプを使用して、そのコードをクリーンアップするでしょうから脇get_or_createのための明白な候補だが、この問題を防ぎますか?

信号はユーザーの操作の後に送信されますが、元の要求が複製されているとは思われません。これは他の操作をトリガーしたためです。

重複が何千回も発生しました。これは必然的に複数の要求によって引き起こされるのでしょうか、あるいは重複したスレッドを作成することができる方法はありますか?そして、重複を防ぐために、きめ細かなトランザクション管理を行う方法がありますか?

Apache2でDjango 1.1、Python 2.4、PostgreSQL 8.1、mod_wsgiを使用しています。

+0

スレッドの安全に対処していないため、私の答えを削除しています。 'MyModel'が何らかの手段で作成された複製を取得した場合、' get'が 'MultipleObjectsReturned'例外を返した場合、複製は継続的に生成されます。 –

答えて

1

おそらくthis answerが役立ちます。どうやら、取引はget_or_createで正しく使用されていますが、これは確認されていません。 mod_wsgiはマルチプロセスとマルチスレッド(どちらも設定可能)です。これは、競合状態が確実に発生する可能性があることを意味します。あなたのアプリケーションで起こっているのは、field1の同じ値を生成する2つの別々のリクエストが起動され、ちょうど正しいタイミングで実行され、 '重複した'エントリを追加するということです。

MyModel(field1=value1, field2=sender)の組み合わせが一意でなければならない場合は、モデルにunique_togetherという制約を定義して、さらに整合性を確保してください。

+0

私に思い出させてくれてありがとう。はい、制約は最終的な問題を解決し、一般的なデータの完全性のための良い考えですが、避けることができれば本番データベースを変更しないようにしたいと思います。 – bennylope

+0

@benny、理解可能ですが、制約がデータレベルで有効な場合は、適用する必要があります。データモデルの間違いはできるだけ早く修正する必要があります。しかし、 'get_or_create'は、トランザクションを使用している間に目的を果たすべきです。 –

2

信号の重複を防ぐには、シグナルアタッチメントコードに「dispatch_uid」パラメータを追加します(described in the docs)。

トランザクションが開かれていることを確認してください。それ以外の場合は、テーブルの状態の確認(objects.get())とcration(save())の間の変更が行われます。

+0

Django 1.1のディスパッチモジュールにはありますが、なぜそれがDjango 1.1のドキュメントに含まれていないのか分かりません。これを試してみよう。 – bennylope

関連する問題