다른 사람이 작업한 user model을 pull해서 다시 user작업을 하게됐다.
모델 필드가 조금 바뀐 것 말고는 크게 바뀌지 않을 거라고 생각했는데
AttributeError: 'User' object has no attribute 'set_password' 이런 오류가 생겼다.
이전에 나는 User model을 만들 때 장고의 AbstractUser model을 이용하여 만들었는데, 이 모델에는 password를 암호화 해주는 set_password가 있다. 하지만 지금은 모델을 직접 커스텀하기 때문에 이 함수를 사용할 수 없다.
#models.py
from django.db import models
class TimestampZone(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
deleted_at = models.DateTimeField(null=True)
class Meta:
abstract = True
class User(TimestampZone):
username=models.CharField(max_length=200, unique=True, default='')
password = models.CharField(max_length=200)
nickname = models.CharField(max_length=100) #닉네임(유저 이름)
url_value = models.CharField(max_length=2000, unique=True)
def __str__(self):
return self.username
그럼 직접 커스텀하는 모델은 어떻데 암호화를 할까?
회원가입
직접 커스텀된 모델의 암호를 해시화하여(암호화하여)저장하기 위해서는 make_password함수를 사용한다.
#serializers.py
from rest_framework import serializers
from accounts.models import User
from django.contrib.auth.hashers import make_password, check_password
from rest_framework_simplejwt.tokens import RefreshToken
class UserSerializer(serializers.ModelSerializer):
class Meta:
model=User
fields=['id','username','password','nickname','created_at','updated_at','deleted_at','url_value']
def create(self, validate_data):
user=User.objects.create(
nickname=validate_data['nickname'],
username=validate_data['username'],
url_value=validate_data['url_value'],
password=make_password(validate_data['password']),
)
# user.set_password(validate_data['password'])
token = RefreshToken.for_user(user)
user.refreshtoken = token
user.save()
return user
이전의 set_password는 주석처리 해줬다.
from django.contrib.auth.hashers import make_password, check_password를 import해줘야 함수가 사용가능하다.
위와 같이 make_password를 사용하면 된다.
참고로 작업할 때 validate_data를 적용하지 않고 password를 바로 함수를 적용해 저장했는데, 그럼 데이터가 잘못 저장된다. 뒤에 로그인 작업할때, 맞는 비밀번호를 입력해도 if 출력이 계속 false로 return한다...
로그인
암호화된 비밀번호를 가져오기 위해 check_password함수를 이용한다.
#serializers.py
class UserLoginSerializer(serializers.Serializer):
username=serializers.CharField(max_length=64)
password=serializers.CharField(max_length=64, write_only=True)
def validate(self, data):
username=data.get("username", None)
password=data.get("password", None)
if User.objects.filter(username=username).exists():
user=User.objects.get(username=username)
hashed_password=make_password('password')
if not check_password(password, user.password):
raise serializers.ValidationError("not id or password")
else:
raise serializers.ValidationError("User does not exist")
token = RefreshToken.for_user(user=user)
data = {
'id': user.id,
'nickname' : user.nickname,
'url_value':user.url_value,
'refresh_token' : str(token),
'access_token' : str(token.access_token)
}
return data
check_password를 사용할 때 주의할 점은, 입력받은 비밀번호와 암호화되어 저장된 비밀번호, 즉 복호화할 유저의 비밀번호 두개의 인자를 넘겨야 한다.
그렇지 않으면 check_password() missing 1 required positional argument: 'encoded' 오류가 난다.
또, AUTH_USER_MODEL='app_name.model_name'또한 삭제 했다. 직접 커스텀한 유저 모델을 사용하면 필요 없음.
views.py는 따로 건드리지 않았다.
pull을 하고나서 models.py에서 TimestampZone모델은 처음 보았다.
나는 유저 모델 안에 time 필드들을 추가했었는데, time관련 필드들은 다른 모델들에서도 계속 사용되어서 아예 모듈화한 듯하다.
참고로 class Meta: abstract=True는 다른 모델들이 이 모델을 상속하기 위해 추가한 것이다.
참고사이트
https://velog.io/@lob3767/Django-Timestamp-modelclass-%EC%83%81%EC%86%8D
'멋사 10기 졸업 프로젝트 > 정리' 카테고리의 다른 글
[Django] django rest-auth패키지를 이용한 유저 기능[2] - login,logout(로그인, 로그아웃) (0) | 2023.01.22 |
---|---|
[Django] django rest-auth패키지를 이용한 유저 기능[1] - register(회원가입) (0) | 2023.01.22 |
[django] simple-jwt방식을 이용한 login, logout 기능 구현 (1) | 2023.01.01 |