# views.py
class UserManage(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
...
# serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'email', 'username', 'password', 'profile_image_url']
def validate_email(self, obj):
if email_isvalid(obj):
return obj
raise serializers.ValidationError('메일 형식이 올바르지 않습니다.')
# utils.py
def email_isvalid(value):
try:
validation = re.compile(r'^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$')
if re.match(validation, value):
return value
raise Exception('메일 형식이 올바르지 않습니다.')
except Exception as e:
print('예외가 발생했습니다.', e)
is_valid
이 실행되는 동시에 serializer의 validate_
로 명명된 해당 필드들이 유효성 검사를 하게 된다.is_valid
이 False로 판명나면 해당 메시지를 클라이언트에 전달하며 회원가입을 할 수 없도록 했다.utils.py
에 저장하여 재사용에 유리하도록 하였다.extra_kwargs = {
'username': {
'validators': [UniqueValidator(queryset=User.objects.all())]
},
'email': {
'validators': [UniqueValidator(queryset=User.objects.all())]
},
}
User.objects.get(email="")
을 통해 회원이 존재하지 않는 경우를 체크해야 했고, 이메일은 괜찮더라도 해당 유저 네임을 이미 사용하고 있는 회원이 있다면 회원가입을 못하게 처리했다.UniqueValidator
를 활용하여 해당 테이블에 존재하는 이메일과 유저네임이 있는지 유효성 검사를 간단히 할 수 있다.# views.py
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(data=serializer.data, status=200)
return Response(data="INFO_INVALID", status=400)
is_valid
를 통해 serializer를 확인하고, 데이터 베이스에 해당 유저 정보를 저장할 수 있다.data="INFO_INVALID
를 담은 response를 전달해도 된지만 좀 더 디테일한 에러 정보를 전달하고 싶었다.raise_exception=True
를 is_valid
뒤에 추가해 주면 raise된 에러를 가시적으로 클라이언트에 전달하는 것이 가능하다.예시1 이메일이 이미 있는 경우
{
"email": [
"This field must be unique."
]
}
예시2 비밀번호가 유효성 검사를 통과하지 못한 경우
{
"password": [
"비밀번호는 8 자리 이상이어야 합니다."
]
}
extra_kwargs = {
'password': {'write_only': True},
}
write_only
를 사용해 쓰기 기능으로만 사용하도록 수정하였다.# views.py
user = User.objects.get(id=request.user.id)
serializer = UserSerializer(user, data=request.data)
User
테이블에서 가져온 유저 객체를 UserSerializer
의 매개변수로 사용해서 존재하는 유저 객체를 담은 Serializer를 생성한다.request.data
를 통해 전달 받는다.# views.py
user = User.objects.get(id=request.user.id)
serializer = UserSerializer(user, data=request.data, partial=True)
pariail=True
를 Serializer 생성에 추가하면 부분적인 .update를 허용하게 되고, 유효성 검사에서 수정하고자 하는 부분만 유효성 검사를 하게 된다.access_token
만 전달해 준다면 email이 있는지 없는지 확인하는 회원가입 Serializer를 재사용하더라도 업데이트 하고자 하는 새로운 정보만 유효성 검사를 하게된다.# views.py
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(data=serializer.data, status=200)
# serializers.py
def update(self, obj, validated_data):
obj.email = validated_data.get('email', obj.email)
obj.username = validated_data.get('username', obj.username)
obj.password = validated_data.get('password', obj.password)
obj.profile_image_url = validated_data.get('profile_image_url', obj.profile_image_url)
obj.save()
return obj
serializer.data
에 접근하기 위해서는 유효성 검사가 필수이며 동시에 업데이트 하고자 하는 정보에 대한 유효성 검사가 필요하므로 .is_valid()
를 통해 유효성 검사를 한다..save()
를 사용하여 인스턴스를 업데이트 한다..save()
는 해당 인스턴스가 데이터 베이스가 존재하는 경우, update 함수를 사용하여 인스턴스를 업데이트한다..get()
을 사용하여 request.data
로 전달 받은 해당 키 값이 있는 경우엔 그 값으로 수정하고, 아닌 경우 본 인스턴스의 정보를 그대로 사용하여 업데이트 하지 않는다.# views.py
class UserManage(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(data=serializer.data, status=200)
return Response(data="INFO_INVALID", status=400)
@login_decorator
def patch(self, request):
user = User.objects.get(id=request.user.id)
serializer = UserSerializer(user, data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(data=serializer.data, status=200)
return Response(data='INFO_INVALID', status=400)
# serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'email', 'username', 'password', 'profile_image_url']
extra_kwargs = {
'password': {'write_only': True},
'username': {
'validators': [UniqueValidator(queryset=User.objects.all())]
},
'email': {
'validators': [UniqueValidator(queryset=User.objects.all())]
},
}
def validate_email(self, obj):
if email_isvalid(obj):
return obj
raise serializers.ValidationError('메일 형식이 올바르지 않습니다.')
def validate_password(self, obj):
if password_isvalid(obj):
return hash_password(obj)
raise serializers.ValidationError("비밀번호는 8 자리 이상이어야 합니다.")
def validate_username(self, obj):
if username_isvalid(obj):
return obj
raise serializers.ValidationError('닉네임은 한 글자 이상이어야 합니다.')
def update(self, obj, validated_data):
obj.email = validated_data.get('email', obj.email)
obj.username = validated_data.get('username', obj.username)
obj.password = validated_data.get('password', obj.password)
obj.profile_image_url = validated_data.get('profile_image_url', obj.profile_image_url)
obj.save()
return obj