2017-09-03 4 views
1

그래서 두 사람 체스 웹 사이트 인 지금 처음으로 장고 프로젝트를 구축하고 있습니다. 나는 거의 끝났어. 이제 시험을 쓰고있어. 이 프로젝트에는 플레이어와 게임이라는 두 가지 독창적 인 모델이 있습니다. 플레이어 모델은 사용자 모델 인 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 

이 모든 주장은 통과하지만 마지막 하나를하지만 마지막 줄에 두 번째 주석을 제거하면, 그것을 전달합니다.

무슨 일 이니? 내가 아는 한, 외래 키 속성 self.player2.current_game을 참조하면 장고는 데이터베이스 조회를 수행하고 최신 필드가있는 Game 인스턴스를 반환합니다. self.game과 self.player2.current_game이 데이터베이스의 동일한 게임 레코드에 해당하고 self.game.refresh_from_db()가 방금 호출 되었기 때문에 self.game.draw_offered == self.player2.current_game.draw_offered라고 생각할 것입니다. True로 평가됩니다. 두 게임 인스턴스는 모두 동일한 데이터베이스 레코드를 참조하며 최신 필드가 있습니다. assertion pass를 만들기 위해 self.player2.current_game.refresh_from_db()를 호출해야한다는 사실은 장고 외래 키에 대한 나의 이해에 따라 self.player2.current_game이 자동으로 업데이트되어야한다. 데이터베이스로

답변

2

이것은 외래 키가 아닙니다.

누락 된 부분은 두 인스턴스가 동일한 데이터베이스 레코드를 가리키고 있기 때문에 동일한 개체라는 것을 의미하지 않습니다. self.game을 새로 고침하여 draw보기에서 기본 레코드의 변경 사항을 확인하는 것처럼 self.player2.current_game도 새로 고쳐야 해당 업데이트 된 값을 가져올 수 있습니다.

장고는 이미 생각을 가지고있는 경우 외부 키를 참조하기위한 데이터베이스 호출을하지 않습니다 그리고 당신은 원래 전체 게임 객체를 전달하여 self.player1self.player2을 만들어 있기 때문에, 않습니다. 그래서 네, 명시 적으로 current_game 객체를 새로 고침하여 변경된 사항을 확인해야합니다.

정말로 원한다면 전체 개체가 아닌 ID를 전달하여이 작업을 수행하지 않고도 개체를 만들 수 있습니다. self.player2 = Player.objects.create(...current_game_id=self.game.id...). 이렇게하면 Django는 실제로 캐시 된 객체를 가지지 않으므로 테스트가 끝날 때 장고에 쿼리해야합니다.

+0

여기 내 이해가있다. x = self.player2라고 쓸 때.current_game, x의 필드는 데이터베이스에 자동으로 업데이트됩니다. Django는 외래 키 속성을 통해 객체를 참조 할 때마다 데이터베이스 조회를 수행하기 때문에 데이터베이스에 자동으로 업데이트됩니다. 답은 self.player2.current_game이 메모리에 저장된 객체를 가리키며 데이터베이스와 아무 관련이없는 표준 Python 속성 참조와 비슷하다는 것을 암시하는 것으로 보입니다. 어느 것이 옳은가요? – Vik78

+1

아니요, 제 3 단락의 시작 부분에서 말씀 드렸듯이 이해가 잘못되었습니다. 처음에 객체의 외래 키 속성을 참조하면 Django는 데이터베이스로 가져와 그것을 가져옵니다. 그러나 부모 개체에 저장하므로 후속 참조로 인해 데이터베이스 조회가 더 이상 발생하지 않습니다. (마찬가지로 처음에'select_related'를 사용했다면 Django는 처음부터 관련된 객체를 얻고 캐쉬하기 위해 JOIN을 할 것이므로 db lookup은 수행되지 않을 것입니다.) 여러분의 경우 다시, Django는 당신이 그것을 만들었을 때, db lookup을 할 필요가 없다. –

+0

{player = request.user.player}를 설정하고 {game = player.current_game}을 (를) 요청하는 많은 조회수가 있으며 그 동작은 {game}의 속성에 따라 다릅니다. {game}의 속성이 최신인지 확인하기 위해 refresh_from_db() 문을 포함하도록보기를 다시 작성해야하거나 외래 키를 참조하여 데이터베이스 조회가 수행 되니? 내 프로젝트가 정상적으로 작동하고있는 것 같아서 {game}의 속성이 오래 되었다면 문제가 발생할 것으로 예상됩니다. 도와 줘서 고마워, btw. – Vik78

0

각 테스트 전에 테스트 러너가 setUp 메소드를 실행하므로 코드를 실행하기 전에 인스턴스에서 작동합니다. 그것은 Unitest 문서에 잘 설명되어 있습니다.

setUp 메서드에서 정의한대로 데이터베이스에서 인스턴스 player2을 새로로드하지 않고로드하는 것입니다.

+0

그래,하지만 그게 왜 중요합니까? player2가 새로 고침되었는지 여부에 관계없이 current_game 외래 키는 데이터베이스의 동일한 레코드를 가리키고, player2.current_game을 호출하면 해당 레코드와 동일한 최신 필드 값을 가진 Game 인스턴스를 반환해야합니다. self.game은 동일한 레코드에 해당하며 데이터베이스에서 새로 고쳐 졌기 때문에 self.game 및 player2.current_game의 필드 값이 같지 않아야합니까? 이 동작에 따라 player.current_game은 필드 값이 데이터베이스에 직접 읽히지 않고 메모리에 저장되는 게임 인스턴스와 유사합니다. – Vik78