스파르타 코딩클럽 내일배움캠프 AI 웹개발자양성과정 3회차
2022.12.21. 79일차 - TIL
1. 프로팔 수정 기능
이전 프로젝트에서 완성하지 못한 프로필 수정 기능을 구현하려 한다. 그때는 백엔드만 성공하고 프론트는 시간이 없어서 완성하지 못했는데 이번에는 시간이 되서 구현하려 한다. 나는 다른 작업을 하고 있었기 때문에 다른 팀원분이 백엔드를 먼저 구현하고, 프론트엔드 연동을 도와 같이 하기로 했다.
class ProfileView(APIView):
...
#프로필 정보 수정하기
def patch(self, request):
user = get_object_or_404(User, id=request.user.id)
serializer = UserEditSerializer(user, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserEditSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["user_nickname", "user_introduce", "user_address", "user_phone", "user_profile_img"]
먼저 다른 팀원이 구현한 코드를 먼저 분석하면 해당 view의 patch method를 정의하고, 먼저 현재 접속한 사용자(request.user)의 id 값을 가진 사용자 객체를 User에서 뽑아낸다. 그리고 전달받은 정보를(request.data)를 UserEditSerializer를 통과시키는데, 해당 시리얼라이저가 통과시키는 필드는 위와 같다. 해당 필드값이 유효하다면(serializer.is_valid) 저장 후(serializer.save) data와 200상태코드를 response하고, 유효하지 않다면 errors와 400상태코드를 response한다. 일단 여기까지는 기존에 했던 백엔드 코드와 유사하니 크게 문제가 되지 않았다.
이제 관건은 프론트와 연동하는 것인데 항상 여기서부터 에러도 많고 이것저것 생각할 것도 많다.(이 영역도 백엔드 영역이겠지....?)
일단 팀원이 해당 view연결 url을 그냥 /users/로 했기 때문에 user id를 뽑을 함수가 필요했고, api.js에 access token에서 user id를 뽑아내는 parseJWT를 만들었기 때문에 현재 접속자를 바로 구할 수 있었다.
//api.js
// 로그인한 user.id 찾는 함수 //
function parseJwt(token) {
var base64Url = localStorage.getItem("access").split('.')[1];
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
var jsonPayload = decodeURIComponent(window.atob(base64).split('').map(
function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
};
//edit.js
const user_id = parseJwt("access").user_id;
그리고 프로필 수정 html이 수정되자 마자 기존에 있던 내용을 그대로 입력란에 붙여넣어야 하기 때문에 다음과 같은 코드를 작성했다. 보면 해당 user 정보를 불러오는 저 부분도 api_user에 따로 있기 때문에 나중에 간결하게 변경해도 좋을 것 같다.
//바로 실행하는 코드
window.onload = () => {
ProfileChange();
}
//기존 정보 표시를 위한 get 호출과 입력란에 값 붙여넣기
async function ProfileChange(){
const response = await fetch(`${backend_base_url}/users/${user_id}/`, {
method: 'GET',
headers:{
Authorization: "Bearer " + localStorage.getItem("access"),
}
})
response_json = await response.json();
document.getElementById("nickname").value = `${response_json.user_nickname}`;
document.getElementById("phone").value = `0${response_json.user_phone}`; //전화번호를 integer로 받아 앞에 0이 사라지기 때문에
document.getElementById("address").value = `${response_json.user_address}`;
if (response_json.user_introduce==null){
let introduce_str = "";
document.getElementById("introduce").value = introduce_str;
} else {
document.getElementById("introduce").value = `${response_json.user_introduce}`;
}
}
//자기소개 50글자 입력 제한
$(document).ready(function() {
$('#introduce_cnt').hide(); //기본적으로 숫자 카운터를 감추었다가
$('#introduce').on('focus', function() { //해당 입력란에 focus가 되면
$('#introduce_cnt').show(); //숫자 카운터를 보여주고
$('#introduce_cnt').html("("+$(this).val().length+" / 50)"); //해당 입력란의 글자수를 보여줌
});
$('#introduce').on('keyup', function() { //입력란에 글자를 입력하면
$('#introduce_cnt').html("("+$(this).val().length+" / 50)"); //해당 입력란의 글자수를 보여줌
if($(this).val().length > 50) { //입력란의 글자가 50글자를 넘으면
$(this).val($(this).val().substring(0, 50)); //입력란의 값을 0~50까지로 설정
$('#introduce_cnt').html("(50 / 50)");
}
});
});
이제 수정하기 버튼을 누르면 동작하는 함수를 구현하면 다음과 같다. 일단 사용자 관점에서 여러가지 오류 상황을 알 수 있는 다양한 alert을 보여주는게 중요하다는 것을 기억하자.
//수정버튼 클릭 시 실행되는 함수
async function ProfileChangeput(){
const nickname = document.getElementById("nickname").value;
const introduce = document.getElementById("introduce").value;
const phone = document.getElementById("phone").value;
const address = document.getElementById("address").value;
const image = document.getElementById('file').files[0] //파일은 value가 아니라 files[0]으로 받는다
//닉네임 공백 확인
if(nickname == "") {
swal("닉네임을 입력해주세요", "", "warning");
return 0;
}
//휴대폰 전화번호 형식 확인 정규표현식(11자리만 가능)
let patternPhone = /01[016789][^0][0-9]{3}[0-9]{4}$/;
if(phone == "") { //전화번호 공백 확인
swal("전화번호를 입력해주세요", "", "warning");
return 0;
} else if(!patternPhone.test(phone)) { //휴대폰 번호가 형식과 일치하는지 확인
swal("핸드폰 번호를 확인 해주세요!", "", "warning");
return 0;
}
//지역입력 확인
if(parseInt(address)==0){
swal("지역을 선택해주세요", "", "warning");
return 0;
}
const form_data = new FormData(); //프로필 이미지 전송을 위한 FormData
form_data.append('user_nickname', nickname)
form_data.append('user_introduce', introduce)
form_data.append('user_phone', phone)
form_data.append('user_address', address) //입력받은 데이터를 form_data에 append
if (image==undefined) { //프로필 이미지가 없다면
response = await patchProfile(form_data); //없는 상태로 form_data를 전송
} else {
form_data.append('user_profile_img', image); //있다면 image를 form_data에 append해 전송
response = await patchProfile(form_data);
}
if (response.status == 200) {
swal("수정되었습니다!", "", "success");
opener.parent.location.reload();
window.close();
} else {
swal("회원정보가 잘못되었습니다.", "", "warning");
return 0;
}
}
참고로 백과 통신하는 api는 다음과 같다.
//프로필 정보 수정 api
async function patchProfile(form_data){
const response = await fetch(`${backend_base_url}/users/`, {
headers:{
Authorization: "Bearer " + localStorage.getItem("access"),
},
method: 'PATCH',
body: form_data
});
return response;
}
'개발일지 > AI 캠프' 카테고리의 다른 글
내일배움캠프 AI - 81일차 TIL, 2022.12.23 (0) | 2022.12.24 |
---|---|
내일배움캠프 AI - 80일차 TIL, 2022.12.22 (0) | 2022.12.24 |
내일배움캠프 AI - 78일차 TIL, 2022.12.20 (0) | 2022.12.24 |
내일배움캠프 AI - 77일차 TIL, 2022.12.19 (0) | 2022.12.20 |
내일배움캠프 AI - 16주차 WIL (0) | 2022.12.19 |