admin에서 선택된 포스트들을 추천 포스트로 올리고 싶습니다. 어떻게 하면 좋을까요? 물론, 일일히 포스트의 상세 정보에 들어가서 해도 되겠지만, 여간 귀찮은 것이 아닙니다. 그럴 때 할 수 있는 것은, admin의 action을 이용하는 것입니다.

 


 먼저, 모델 Post는 위와 같습니다. user는 FK로 정의되어 있습니다. 다음에 content, created, view, recommend_flag가 정의되어 있습니다.

 

 

 다음에 Action이라 하면, Action 밑에 뜨는 것들을 말하는데요. 예를 들자면, Delete selected posts라고 하면, 선택된 포스트들을 모두 삭제합니다. 이를 한 번에 처리할 수 있는 것이 action인 셈입니다. 문제에서의 요구 사항은 선택된 post들의 recommend flag를 모두 참으로 바꿔버리는 것입니다.

 

  먼저, actions에 "set_recommend_flag"를 추가합니다. 44번째 줄입니다. 다음, 46번째 줄에 @admin.action 데코레이터를 추가하였어요. description에 "set recommend flag"를 적어주었습니다. 다음에 47번째 줄에 함수 명을 set_recommend_flag라고 적어주었습니다. actions에 적어준 이름과 똑같이 적어주었어요.

 

 48번째 줄이 핵심인데요. queryset.update(recommend_flag=True)라고 적어주었습니다. 일단, set_recommend_flag를 탈 때 queryset에 어떤 쿼리가 들어가는지 디버그로 찍어봐야겠네요. 문서에 따르면 선택된 row에 대해 업데이트를 한다고 되어 있기 때문입니다.

 

 3번과 5번을 선택하겠습니다.

 

 그러면 set_recommend_flag 함수에 들어오는 queryset의 query는 위와 같아요. 중요한 부분은, where 부분의 in 절인데요. id가 3, 5에 속하면 선택됨을 의미합니다. 따라서, app_post에 있는 레코드 중, id가 3, 5에 속하는 것을 select 한 다음에 update를 하게 됩니다.

 

 이를 확인해 봅시다. 현재 1 ~ 6번 post의 recommend_flag가 모두 0임을 확인할 수 있습니다.

 

 48번째 줄을 실행한 후에 어떻게 변할까요?

 

 

 3과 5가 선택되었습니다. 그리고 이들이 update 되게 됩니다. 다른 포스트 2개를 임의로 선택해서 업데이트 해 보겠습니다.

 

 silk로 프로파일링을 해 보니, 위와 같은 쿼리가 보입니다. 실제로 업데이트 쿼리가 날라갈 때 id 값을 in 절에 넣는 것을 알 수 있어요.

 


 그런데 여기서 하나 궁금한 점이 생겼습니다. in 절에 들어가는 것이 많을수록 쿼리는 상당히 느려집니다.

 

 포스트가 3952개가 있었어요. 이 포스트들을 모두 선택한 다음에 set recommend flag action을 수행하면 쿼리셋이 어떻게 날라갈까요? 그저, 3952개의 포스트의 id를 in절에 때려넣을까요? 아닙니다. 실제로 debug에서 확인해 보면 아래와 같은 쿼리셋이 들어갑니다.

 

 모든 포스트를 선택한다. where절이 따로 없습니다. 실제 update 쿼리가 어떻게 들어가는지 보겠습니다.

 

 where절이 없는 update set이 들어갔습니다.