중요한 내용을 배우기 전에 이야기를 한 번 해보자.
우리는 웹 서비스를 개발할 때에, 여러 기능이 필요할 것이다.
Instagram을 개발한다고 할 때 어떤 기능을 더 구현해야할까? 우리는 충분히 글과 그림의 게시글을 작성, 조회, 수정, 삭제 등을 할 수 있다. 이런 기능의 근본적인 목적은 사람들간 소통을 하기 위함이다. 팔로우 기능, 좋아요 기능, 댓글 기능까지도 구현해보려 한다. 그 전에 우리는 User라는 사용자 객체를 만들어 DB에 저장하고, 로그인 기능을 먼저 구현해야할 것이다.
HTML 문서와 같은 리소스들을 가져올 수 있도록 해주는 규약
비 연결 지향 : 서버는 요청에 대한 응답을 보낸 후 연결을 끊음
무상태 : 연결을 끊는 순간 클라이언트와 서버 간의 통신이 끝나며 상태 정보가 유지되지 않음
쿠키 : 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각
세션 : 서버 측에서 생성되어 클라이언트와 서버 간의 상태를 유지, 상태 정보를 저장하는 데이터 저장 방식
쿠키와 세션의 목적은 결국 서버와 클라이언트 간의 상태를 유지하기 위함이다.
이젠 계정을 관리하는 앱을 만들어보자.
$ python manage.py startapp accounts
# 이후 앱 등록 + urls 연결까지 진행
이제는 Django의 권장사항을 하나 따라야 하는데, Django에서 기본적으로 제공하는 User model을 Custom해야한다. 그 이유는 내장 User model은 auth에 내장된 User 클래스를 사용하는데 이는 우리가 원하는 column을 이후에 변경하거나 추가하기 힘들기 때문에 최초에 CustomUsermodel을 만들어야한다. 결국 최초 언급했던 우리가 framework 덕분에 편하게 유저에 대한 데이터를 다룰 수 있지만 직접 수정할 수 없는 문제도 있다는 것이다. 그럼 어떻게 커스텀 하는지 알아보러 가보자.
모델 설정
프로젝트 전체에서 바라보는 유저 바꾸기(auth.User -> accounts.User)
관리자 페이지에서 User 만들 수 있도록 설정
우린 처음에 Django에서 기본적으로 제공하는 User는 사용해보기도 전에 커스텀해버렸다. 왜 그렇게 커스텀하는 것이 중요할까? -> 프로젝트 중간에는 AUTH_USER_MODEL을 변경할 수 없다. 이미 프로젝트가 진행되고 있다면? -> DB를 초기화 한 이후 진행해야한다.
Session을 Create하는 과정
로그인 인증에 사용할 데이터를 입력받는 built-in form
CRUD 과정에서 익숙한 형태의 코드일테지만 views.py의 내용은 중요하고 많다보니 같이 들여다보자. 우리는 로그인이라는 기능 또한 django의 auth가 제공하는 기능을 사용할 것이니 login이라는 것을 import 받는데 우리는 login이라는 이름의 view 함수를 사용할 것이므로 이름을 auth_login으로 수정하며 시작하자. 유저의 입장에서 로그인이라는 페이지로 들어오면 이는 GET 요청으로 비어있는 AuthenticatedForm을 제공할 것이다. 그럼 유저는 빈 폼에 아이디와 비밀번호 정보를 입력하여 제출을 할 것이며 이는 POST요청이 될 것이다. 그럼 입력받은 정보를 담은 폼을 유효성 검사를 거친 후 로그인을 시키는데 이때, 필요한 인자는 request와 form.get_user() 2개이다. 그리고 로그인 완료 되었으면 INDEX 페이지로 돌려보내자.
AuthenticationForm 을 통해 인증된 사용자를 로그인하는 함수
get_user() : AuthenticationForm의 인스턴스 메서드로, 유효성 검사를 통과했을 경우, 로그인한 사용자 객체를 반환
view함수의 이름과 겹치지 않도록 주의(재귀 오류) -> 위에선 auth_login으로 바꿈
Session을 Delete하는 과정
현재 요청에 대한 Session Data를 DB에서 삭제, 클라이언트의 쿠키에서도 Session Id를 삭제
view함수의 이름과 겹치지 않도록 주의(재귀 오류) -> auth_logout으로 이름 바꾸기
User객체를 Create 하는 과정
회원가입시 사용자 입력 데이터를 받을 built-in ModelForm
로그인에서는 분명 built-in form을 사용했는데 왜 회원가입은 ModelForm을 사용하는가?
우리가 처음 ModelForm을 학습할 당시를 떠올려보면 그 기준이 생각날 것이다. 로그인이라는 과정은 조회에 해당하지만 회원가입은 생성에 해당하여 DB에 저장해야할 것이다. 이렇게 DB에 영향을 주는 기능은 ModelForm을 활용하기로 했었다.
의 코드 해석은 여러분께 맡긴다. 주목할 점은 UserCreationForm은 1개의 변수만을 갖는다.
그리고 DB에 저장하는 과정도 거치게 된다. 그렇게 회원가입을 진행하게 되면?
이러한 오류가 발생하게 된다. 읽어보면 우리가 바꾼 User모델인 CustomUsermodel이 아닌 기존 Usermodel을 참조하고 있다고 한다. 생성 과정과 우리가 아직 만들지 않았지만 수정 과정은 ModelForm을 사용하기 때문에 이는 자동으로 Meta 클래스에서 User를 참조하고 있으므로 Custom을 통해 Meta의 model을 수정해야한다.
수정하고 views.py에서도 수정을 진행하면 또 다른 문제에 봉착한다.
회워가입에서 볼 수 없는 옵션들도 유저에게 하여금 선택가능하다. 이는 제제를 할 필요가 있어보인다. 필요한 fields만 남겨두자. 비밀번호는 따로 관리하므로 넣지 않아도 자동으로 만들어준다.
이정도면 충분한 것 같다. 위에서 get_user_model()로 우리는 모델을 참조하고 있다 분명 models.py에서 정의한 User 클래스를 써도되고, settings.py의 AUTH_USER_MODEL을 참조해도 되지만 이 또한 권장사항으로 get_user_model()을 사용하자 이는 메서드이므로 괄호를 붙여야 한다. 정확한 의미는 "현재 프로젝트에서 활성화된 사용자 모델"을 반환하는 함수이다.
User 객체를 Delete 하는 과정
한 가지만 언급하고 넘어가겠다. POST 요청 보내는 request에 담겨있는 회원 정보를 지우고 싶다면 request.user로 접근하면 된다.
회원정보 수정 시 사용자 입력 데이터를 받을 built-in ModelForm
게시글의 수정과 비슷하게 instance 인자를 사용하고 있는 모습이고, ModelForm에 대한 설정을 다시 보자면 비밀번호 수정을 넣지 않았다. 하지만 수정을 들어가보면 비밀번호 수정란이 뜨는 것을 볼 수 있다. 이는 Django에서 따로 관리하기 때문인데 수정을 하면 Error 화면을 보여준다. 이를 해결하러 가보자.
인증된 사용자의 Session Data를 Update하는 과정
비밀번호 변경 시 사용자 입력 데이터를 받을 built-in Form
짚고 넘어가야할 내용은 2가지로 보인다. 첫째 비밀번호는 DB에 저장될까? 그렇다면 ModelForm일텐데? Form이네? 그렇다 비밀번호는 DB에 그대로 저장되지 않는다. 둘째는 비밀번호 변경에 대한 url은 project urls.py에 작성함을 볼 수 있다. 이를 주의하자.
추가로 혹시 비밀번호를 변경하면 기존 세션과의 정보가 달려저서 로그아웃 처리됨을 알 수 있는데 난 변경을 해도 로그아웃 상태를 유지하고 싶다고 한다면 update_session_auth_hash 메서드를 사용해볼 수 있다.
그렇다면 우리는 User에 대한 긴 학습을 마쳤고 뿌듯한 마음으로 index 홈페이지로 들어가보자.
로그인, 로그아웃, 회원가입, 회원정보 수정, 회원탈퇴 등을 해보면 혹시 이상한 점이 있지 않은가? 가장 불편한 점은 내가 로그인이 되어있는지 아닌지를 알 수 없으며, 로그인을 해도 로그인 창을 들어갈 수 있고, 회원가입 창을 갈 수 있으며, 로그아웃 상태에서도 회원탈퇴 버튼이 보이고 있다. 이를 어떻게 해결할 수 있을까? 적어도 내가 로그인 상태인지 아닌지 정도는 구분하고 싶다. 여기엔 2가지 방법이 있다.
사용자가 인증 되었는지 여부를 알 수 있는 User model의 속성
모든 User 인스턴스에 대해 항상 True인 읽기 전용 속성이며, 비인증 사용자에 대해서는 항상 False
DTL의 조건문을 활용하여 로그인 상태 여부를 간접적으로 확인할 수 있도록 설정. 하지만 url로 접근하는 것은 막을 수 없기 때문에 한 가지 조건을 더 달아주자.
인증된 사용자에 대해서만 view 함수를 실행시키는 데코레이터
비인증 사용자의 경우 /accounts/login/ 주소로 redirect 시킴
긴 시간동안 한 번에 User를 어떻게 model을 정의하고 CRUD 하는지에 대해 알아보았다. 게시글의 CRUD와 코드는 비슷하지만 차이점도 분명 존재하였기 때문에 외우려하기보단 코드를 이해하려는 공부를 하는 것이 좋을 것이다. 이후에는 좋아요기능, 댓글기능, 팔로우 기능 등을 알아보도록 하자.