53

私のアプリケーションでは、新しいユーザーがサインアップしたときに特定のテーブルにエントリを作成したいと思います。たとえば、会社やその他のレコードを参照するユーザープロファイルを作成したいと思います。post_saveシグナルでこれを実装しました:

def callback_create_profile(sender, **kwargs):
    # check if we are creating a new User
    if kwargs.get('created', True):
        user = kwargs.get('instance')
        company = Company.objects.create(name="My Company")
        employee = Employee.objects.create(company=company, name_first=user.first_name, name_last=user.last_name)
        profile = UserProfile.objects.create(user=user, employee=employee, partner=partner)
# Register the callback
post_save.connect(callback_create_profile, sender=User, dispatch_uid="core.models")

これは実行時にうまく機能します。adminを使用して新しいユーザーを作成でき、他の3つのテーブルも適切なエントリを取得します。(つまり、user.first_nameとuser.last_name以降の従業員は、保存時に管理者のフォームに入力されません。なぜそのように行われるのかはまだわかりません)

テストスイートを実行したときに問題が発生しました。この前に、テーブルにこれらのエントリを作成するための一連のフィクスチャを作成していました。ここで、次のようなエラーが発生します。

IntegrityError: duplicate key value violates unique constraint "core_userprofile_user_id_key"

これは、IDが「1」のフィクスチャに会社、従業員、およびプロファイルレコードをすでに作成していて、post_saveシグナルがそれを再作成しようとしているためだと思います。

私の質問は次のとおりです。フィクスチャを実行しているときにこのpost_saveシグナルを無効にできますか?テストスイートの一部として実行していて、これらのレコードを作成していないことを検出できますか?これらのレコードをフィクスチャから今すぐ削除する必要がありますか(信号はデフォルトを設定するだけで、テストしたい値は設定しません)?フィクスチャのロードコードが作成されたレコードを上書きしないのはなぜですか?

人々はこれをどのように行うのですか?

4

4 に答える 4

80

私はこれを行う方法を考え出したと思います。シグナルとともに渡されるkwargsには「raw」パラメーターがあるため、上記のテストを次のテストに置き換えることができます。

if (kwargs.get('created', True) and not kwargs.get('raw', False)):

loaddataの実行中にRawが使用されます。これでうまくいくようです。

ここに記載されています:http://code.djangoproject.com/ticket/13299

これが文書化されていればいいでしょう:http://docs.djangoproject.com/en/1.2/ref/signals/#django.db.models.signals.post_save

于 2010-08-17T06:57:18.737 に答える
23

これは古い質問ですが、私が最も簡単に見つけた解決策は、ロードデータによって渡される「raw」引数を使用し、リスナー関数を装飾することです。次に例を示します。

from functools import wraps


def disable_for_loaddata(signal_handler):
    @wraps(signal_handler)
    def wrapper(*args, **kwargs):
        if kwargs['raw']:
            print "Skipping signal for %s %s" % (args, kwargs)
            return
        signal_handler(*args, **kwargs)
    return wrapper

その後

@disable_for_loaddata
def callback_create_profile(sender, **kwargs):
    # check if we are creating a new User
    ...
于 2012-07-10T08:53:18.240 に答える
13

簡単な解決策、これをpost_save関数の先頭に追加します。

if kwargs.get('raw', False):
    return False

これにより、フィクスチャをロードするときにこの関数が終了します。

参照:https ://docs.djangoproject.com/en/dev/ref/signals/#post-save

于 2014-02-10T17:15:33.560 に答える
3

私のプロジェクトの1つで同様の問題に直面しました。私の場合、信号によってテストも遅くなりました。Model.save()代わりにメソッドをオーバーライドするために、シグナルを放棄することになりました。

ただし、あなたの場合、メソッドをオーバーライドしてこれを実現することは意味がないと思いますsave()。その場合は、これを試してみてください。警告、私は一度だけそれを試しました。動作しているように見えましたが、十分にテストされていません。

  1. 独自のテストランナーを作成します。
  2. フィクスチャをロードする前に、クラスの信号から機能を 切断してください。callback_create_profileUserpost_save
  3. フィクスチャをロードします。
  4. 関数を信号に接続し直します。
于 2010-08-17T06:40:09.067 に答える