학습주제
사용자와 인증
Serializer를 이용한 유저 생성
학습내용
지난시간엔 view를 통한 화면으로 유저를 생성하였다.
우리는 JSON으로 동작하는 API 서버도 만들고 있기 때문에 회원가입도 API 서버를 통해 구현 가능해야 한다.
우선 사용자를 등록하는 Serializer를 만들어본다.
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username', 'password']
extra_kwargs = {'password' : {wirte_only:True}}
password는 쓰는 것만 가능함.
이렇게 만든 시리얼라이저를 가지고 뷰를 만든다.
class RegisterUser(generics.CreateAPIView):
serializer_class = RegisterSerializer
위에 import도 * 로 바꾸어 RegisterSerializer도 불러왔다.
이렇게 만든 뷰를 url에 등록해준다.
그 후 페이지에 접속하면
"detail": "Method \"GET\" not allowed."
은 우리가 view를 만들 때 상속을 generic.CreateAPIView로 만들었기 때문이다.
만일 리스트와 생성이 같이 있는 ListCreateAPIView로 만들어보면
queryset = User.objects.all()
우리는 보통 유저를 만들 때 리스트를 보지 않으므로 CreateAPIView로 돌아온다.
근데 왜 UserList에서 그냥 한꺼번에 유저를 등록하는 기능도 넣지 않고 따로 클래스를 만든 이유는 serializer_class를 만들 때 시리얼라이저에서 원하는 필드, 제한사항을 추가하고 싶기 때문이다.
비밀번호가 password로 생성되었다. 이번에는 별도로 제한사항이 언급되지 않고 생성되었다.
user2 를 다시 생성하면, 같은 이름의 유저가 있다고 한다.
코드에 그 에러메세지가 어디에 구현되어 있는지 살펴본다.
여기 User 모델에 구현되어 있다. Ctrl을 누르고 들어가 User가 구현된 부분을 본다.
다시 AbstractUser로 넘어간다.
보면
username_validator = ~~Validator()
가 동작하게 되어있는데 중복 유저를 체크한다.
Django의 auth 앱으로 구현했을 때와 마찬가지로 password를 막는 작업을 해보려 한다.
from django.contrib.auth.password_validation import validate_password
를 임포트하여 우리가 만든 RegisterSerializer에 넣어주려 한다.
이때 별도의 password라는 변수를 만들어준다.
password = serializers.CharField(write_only=True, required=True, validators=[validate_password])
wirte_only 쓰기만 가능.
required 무조건 입력해야함.
validators 검증방식 = 아까 import한 validate_password
이러한 필드를 별도로 구현한다. 그럼 전에 만들어 놓은 extra_kwargs는 필요없다. 더 강화했기 때문.
user3를 비밀번호 12341234로 생성하니
숫자로 구성되어 있다며 validator가 validate_password 방식으로 막았다.
이제 password를 두개 입력받아서 일치하는지 확인하는 기능을 구현해보려고 한다.
시리얼라이저 내에 validate을 구현하면 우리가 원하는 validate을 구현할 수 있다. (오버라이딩)
attr은 화면에서 전달받은 값들의 딕셔너리 형태이다. 그 중 'password'를 키, 실제 입력값은 value로 정의된다.
지금은 비밀번호를 한번 더 입력받게 하여, 그 두 값을 비교하는 작업을 한다.
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True, validators=[validate_password])
password2 = serializers.CharField(write_only=True, required=True)
def validate(self, attrs):
if attrs['password'] != attrs['password2']:
raise serializers.ValidationError({"password":"두 패스워드가 일치하지 않습니다."})
return attrs
class Meta:
model = User
fields = ['username', 'password', 'password2']
password2 필드를 만들었다면, fields에도 꼭 넣어주어야 한다.
fields는 출력 순서하고도 연관이 있다.
시리얼라이저가 이 정보로는 유저를 만들 수 없다고 한다. 그 이유는 User모델에는 password2가 존재하지 않기 때문에 fields 에 있는 password2 값을 넣을 곳이 없다.
따라서 전에 validate를 직접 만들어 준 것처럼, create도 만들어준다.
def create(self, validated_data):
user = User.objects.create(username=validated_data['username'])
user.set_password(validated_data['password'])
user.save()
잘 만들어진다.
UserSerializer에 같이 구현하지 않고 별도로 RegisterSerializer를 만든 이유는 별도의 validate, create 정의가 필요했기 때문이다.