2017-09-03 5 views
1

今私は最初のDjangoプロジェクトを作成しています.2人のチェスのWebサイトです。私はほとんど終わっており、今はテストを書いています。このプロジェクトには、プレイヤーとゲームの2つのオリジナルモデルがあります。プレイヤーモデルは、Userモデル、Player.user、そしてプレーヤーが現在であるゲームのインスタンスを示しゲームへの外部キー、Player.current_gameに一対一のフィールドを持つ。Game.draw_offered CharFieldですが値をとります「」抽選が提供されたかどうか、およびそれを提供したプレーヤーの色を示す「デフォルト」(デフォルト値)、「w」、または「b」である。Djangoの外部キーの仕組みを理解しようとしています

class Draw_ViewTestCase(TestCase): 

    def setUp(self): 
     self.user1 = User.objects.create_user(username="Test_User_1", password="test1") 
     self.user2 = User.objects.create_user(username="Test_User_2", password="test2") 
     self.factory = RequestFactory() 
     self.game = Game.objects.create() 
     self.player1 = Player.objects.create(user=self.user1, current_game=self.game, color="w") 
     self.player2 = Player.objects.create(user=self.user2, current_game=self.game, color="b") 

    def test_draw(self): 
     request = self.factory.get(reverse('draw')) 
     request.user = self.user1 
     #The draw view changes the draw_offered field of the player's current game to the player's color, and saves the current_game to the database 
     response = draw(request) 
     self.game.refresh_from_db() 
     assert self.game.draw_offered == self.player1.color 
     assert self.game == self.player2.current_game 
     #self.player2.current_game.refresh_from_db() 
     assert self.game.draw_offered == self.player2.current_game.draw_offered 

すべてのアサーションが合格したが、最後の1をしていますが、最後の行に2つ目のコメントを解除した場合、それが通過する:私は、次のないテストケースを持っています。

何が起こっているのですか?私が理解しているように、外部キー属性self.player2.current_gameを参照すると、Djangoはデータベースルックアップを実行し、最新のフィールドを持つGameインスタンスを返します。 self.gameとself.player2.current_gameはデータベースの同じゲームレコードに対応し、self.game.refresh_from_db()が呼び出されたばかりなので、self.game.draw_offered == self.player2.current_game.draw_offeredどちらのゲームインスタンスも同じデータベースレコードを参照し、最新のフィールドを持っています。アサーションパスを作るためにself.player2.current_game.refresh_from_db()を呼び出さなければならないという事実は、私には意味をなさない - Djangoの外部キーについての私の理解によれば、self.player2.current_gameは自動的に更新されるべきであるデータベースを使用します。

答えて

2

これは外来キーに関するものではありません。

あなたが欠けているのは、2つのインスタンスが同じデータベースレコードを指しているからといって、それらが同じオブジェクトであるということではありません。 self.gameをリフレッシュして、drawビューの基になるレコードに加えられた変更を確認するのと同様に、更新された値も取得するように、self.player2.current_gameを更新する必要があります。

Djangoは、それが既にそれを持っていると思えば、外部キーを検索するためのデータベース呼び出しを行いません:それは元々self.player1self.player2をGameオブジェクト全体に渡して作成したからです。ですから、変更を確認するためにcurrent_gameオブジェクトを明示的にリフレッシュする必要があります。 self.player2 = Player.objects.create(...current_game_id=self.game.id...)を:あなたが本当に望んでいた場合は

は、おそらく完全なオブジェクトではなく、IDを渡すことによって、これを実行せずにオブジェクトを作成することができます。この方法では、Djangoは実際にオブジェクトをキャッシュしないので、テストの最後にDjangoに問い合わせる必要があります。

+0

これは私の理解です。あなたがx = self.player2と書くとき。current_gameでは、外部キー属性を介してオブジェクトを参照するときはいつでも、Djangoはデータベース参照を実行するため、xのフィールドは自動的に最新のデータベースに更新されます。あなたの答えは、self.player2.current_gameがメモリに格納されたオブジェクトを指し、データベースとは何の関係もない標準のPython属性参照によく似ていることを暗示しているようです。どちらが正しいか? – Vik78

+1

いいえ、あなたの理解は間違っています、私が第3段落の冒頭で言うように。あなたが最初に*オブジェクトの外部キー属性を参照すると、Djangoはそれをフェッチするためにデータベースに行きます。ただし、それを親オブジェクトに格納するため、後続の参照でそれ以上のデータベース検索が行われることはありません。 (同様に、最初に 'select_related'を使用した場合、DjangoはJOINを実行して関連するオブジェクトを最初から取得してキャッシュしますので、dbの参照は行われません)あなたの場合、Djangoはあなたがそれを作成したときに、dbルックアップを行う必要はありません。 –

+0

{player = request.user.player}、{game = player.current_game}のようなリクエストを受け取るビューがたくさんあり、その動作は{game}の属性に依存します。 {game}の属性が最新であることを保証するためにrefresh_from_db()文を含めるようにこれらのビューを書き直す必要がありますか、または外部キーを参照することでデータベースの参照が保証される特定の状況があります実行されるか?私のプロジェクトはそれなりにうまくいっているようですが、{game}の属性が古くなったら問題があると思います。あなたの助けてくれてありがとう、btw。 – Vik78

0

テストランナーは、各テストの前にsetUpメソッドを実行するため、コードを実行する前からインスタンスで操作しています。それはUnitestのドキュメントでよく説明されています。

setUpメソッドで定義されているように、データベースから新規のplayer2インスタンスにアクセスするのではなく、ロードするだけです。

+0

ええ、それはなぜ重要ですか?かかわらず、player2が更新であるかどうかの、データベース内の同じレコード、および呼び出しplayer2.current_gameへのcurrent_game外国のキーポイントは、そのレコードと同じ最新のフィールド値でゲームのインスタンスを返す必要があります。 self.gameは同じレコードに対応し、データベースから更新されたばかりなので、self.gameとplayer2.current_gameのフィールド値は同じであってはいけませんか?この動作に基づいて、player.current_gameは、フィールド値がデータベースに直接読み込まれるのではなく、メモリに格納されるゲームインスタンスのように機能します。 – Vik78

関連する問題