제수기 - 제발 수업내용을 기억해라 / 단순수업정리 시리즈
아아.. 어제 아파서 수업을 제대로 못들었더니 많은 부분을 놓쳐버렸다... 중요한 내용 같았는데.. (어제 놓친 거 : 계층형 Architecture 구성, Qestion 상세보기 페이지 구현하기, Question 등록하기, Paging 처리하기
)일단 내꺼에서 계속 에러가 나서, 어디가 문제인지 알기 전에 수업진도부터 따라가야 하므로 내 폴더를 지우고 강사님 폴더를 복붙! 하지만 Git 과정에서 오류 발생! 해결하고 다시 폴더 복붙! 그러나 결과창이 강사님과 내것이 다른 상태!
아무튼 헐레벌떡 따라가면서.. 지금 배우는 거라도 정리 시작!ㅠㅠ
상태창이 달랐던 이유. django shell에서 정보를 추가했었기 떄문.
이제 페이지가 여러개로 나타난다.
💥
setting의 auth_suer.is_staff = 1
기능에 대해 설명해주셨는데.. 제대로 못들었다.
python manage.py createsuperuser
끝에 부분을 qna/
가 아니라 admin/
을 치면 이런 화면이 나온다. makemigrations 뒤에 앱을 안 쓰면 전체로 실행이 된다. 그래서 빼고 진행하면 이제 전체 앱을 대상으로 실행이 돼서 admin 창을 볼 수 있다.
config
settings.py
, urls.py
에 이미 admin 설정이 돼 있다.
db 중에 auth_user에 user 정보를 넣을 수 있다.
터미널에 python manage.py createsuperuser
치고, 사용자 이름 쓰라고 하면 admin
으로 그냥 쓰기로 했다.
이메일 주소: admin@encore.com
password: 1234 (숫자가 안 보여도 써지고 있는 거라서 그냥 쓰고 엔터 누르면 된다.)
(단순 관리자가 staff 라고 돼있다.)
회원 등록 안 될 경우, auth_user table 우클릭
테이블 수정,
last login - Not Null 클릭 해제
전체 마이그레이션이 안됐어서 발생하는 오류
이렇게 써도 되고
우리는 이렇게 쓰도록 하자.
로그인해서 보면 페이지가 이렇게 나온다.
이 모든 과정에서.. 해당 링크를 참고하도록 하자. https://docs.djangoproject.com/en/5.1/ref/contrib/admin/
question 직접 추가할 수도 있다
인증과 인가 구별하기
-인증 Authentication 등록된 사용자 증명
-인가 Authorization 인증된 사용자가 이 작업을 할 권한이 있다.
ex 신분증 검사
신분증 사진과 실제 얼굴을 비교하는 게 인증. 숫자를 보고 술을 살 수 있는지 성인 여부를 판단하는 인가 작업이 이뤄짐.
uauth
앱을 만들자.
auth
는 django
에 이미 있는 앱이라서 안 만들어진다.
만들어서 _04_qna > urls.py
에 path
를 uauth/
의 uauth.urls
로 설정해야 한다. 이 말인 즉슨, 💥(어떤 요청이 오면) uauth.urls로 반환하겠다는 뜻.
uauth
의 urls.py
에도 코드 적어주면서
urls 연결 완료!
이제 파이썬 패키지를 만들어준다.
controller
에는 기존에 만들어져있던 views.py
를 옮겨주고, entity
에는 models.py
를 옮겨준다.repositoy
랑 service
에는 각각 uauth_repository.py
와 uauth_service.py
를 만들어서 넣어준다.💥service, repository에 인터페이스와 ?를 구현해보자.
💥 아래에서 뭘한건지 잘 모르겠다. 흐름이 이해가 안 간다.
에러
이제 template에 가서 uauth 경로와 그 안에 login.html 파일을 만들어준다.
💥post 타입
에러
html에서 extends layout.
으로 써서. 이걸/
로 바꿔줬다.
요청을 보낸 포스트 컨펌이 페이지가 왔다는 걸 검증한다.
setting에 가서 로그인 성공 후 리다이렉트 페이지 지정
question_form.html
내용 일부({% if form.errors %}
이하 ~)를 잘라서
form_errors.html
에 넣는다.
login.html에서는 홈페이지 오류를 출력할 수 있게 {% include '../layout/form_errors.html %}
을 넣었다.💥 근데 애초에 question_form.html을 include하면 안됐던 건가? 왜 굳이 form_errors.html에 옮겨서 하는거지?
화면에는 에러창이 잘 뜬다.
tip 강제 로그아웃하는 방법! 개발자도구에서 Application에서 Cookies에서 x자 눌러주면 강제 로그아웃 됨!
user. 사이트
user. 어쩌구저쩌구는 다 여기에 모아져있다.
https://docs.djangoproject.com/en/5.1/ref/contrib/auth/
우리는 지금까지 urls한테 우리 이거 쓸게.. 한 게 다다. 정말 간단히 구현해낸 것.
header_html
에 if user.is_authenticated
를 사용했다. 💥부가설명 GPT
💥uauth의 urls.py에서 path를 지정해준다. path logout은 views.logout 이렇게 간단한데 왜 path login에서는 저렇게 복잡해진거지..?
💥redirect(index)가 뭐임.. GPT 나와!
이제 로그아웃이 된다.
사이트마다 다르게 / 가끔씩 다르게 바꿔줘야 덜 털린다.
UserAttributeSimilarityValidator
: 유저 정보와 다른 정보가 비슷한지 여부 검사MinimumLengthValidator
: 최소 길이에 대한 제한CommonPasswordValidator
: 일반적이고 단순한 비밀번호 막음NumericPasswordValidator
: 숫자값으로 이뤄져있는지 확인하지만 개발 편의성을 위해 다 꺼놨다가 나중에 배포하기 전에 다시 수정하는 게 좋다.
그래도 열어보면 암호화처리는 다 돼있다. 개발자들도 사용자들의 비밀번호를 볼 수 없어야 한다.
💥render(request, 'uauth/singup.html'이게 뭐임!
signup.html
UserDetail
과 user
가 OneToOneField
관계다. 1:1 관계다. user 하나당 userdetail 하나를 가질 수 있다.
사용자 입력값을 퍼다 나르기 위해서 존재하는 클래스가 Forms
view와 template 사이를 유하게 해줄 수 있다.
유효성 검사, 에러메세지 처리 이런 것도 다 된다.
user form을 사용해서 모델을 만들자. 모델만 있어서는 자세한 정보를 넣을 수 없다.
폼에서는 모델을 유저로 보고 있다.
class Meta: model=User
홈페이지 요구할 때는 Get
다른 뭐.. 할 때는 POst..
에러메시지 확인
유효성 검사까지 해서 유효하지 않더라도 다시 랜더하게
둘 다 벌쓰데이, 프로필 키값을 달라느 ㄴ건데, 밑에처럼 get으로 달라고 하면 키값이 없어도 오류가 나지 않고 null
print(난다) 위에는 블랭켓 해서 널이 안 들어간다. 널러블한 아래만 그렇게 한거고
user, userdetail
마이그레이션
db 테이블이 생성된다.
회원가입 다시 해봤더니 뜨는 에러
이 부분 지우고 다시 하니까 잘 됐다.
회원가입을 진행하면 만들어진 테이블로 정보가 들어오는 걸 볼 수 있다.
message
여기서 복붙
어트리뷰터 에러 해결
저장된 파일의 경로만 DB에 저장된다.
위쪽에 있는 BASE_DIR 위치 확인한 다음에
경로 생성
config ulrs.py settings에 있는
upload to =
default = 사진 안 넣을 경우 기본값으로 나타날 사진 / 근데 구현이 제대로 안돼서 나중에 삭제했음.
이제 회원가입에서 사진을 넣고 가입하면, 자동으로 profile 경로에서도 사진을 확인할 수 있고
테이블 profile에서도 확인할 수 있다. 이미지 이름은 원래 저게 맞다. 캡처본 사용했다.
순서 설정해주신 거 그대로 작성.. 추후 정리 필요
장고에는 파일 업로드 기능이 활성화가 안 돼있다.
settings 파일에 mida url, media root 설정이 필요하다.
root 는 전체 경로가 필요해서 만들어놓은거고
surls에 스테테ㅣㄱ 함수 해서 추가해준다. 여기에 스테틱을 준거다. settings.MEDIA_URL이 뭐하는 앤가. 사용자랑 뷰하고 연결해준거. 근데 여기 왜 적었냐. 나중에 업로드한 파일ㅇ르 실제 클라이언트한테 요구하면 이름이 meidia/profiele/xxx.jpg 이렇게 될텐데 이것도 스테틱 파일처럼 처리해라 라는 얘기다. 장고에 어플리케이션 쪽 뷰 쪽 경로 타지 말고 바로 여기 루트쪽 가서 읽어주세요. 라고 요청한 것.
settings.py 나중에 업로드할 거 여기에 저장할게요
업로드시 주의사항은
학생들이 singup.html에 enctype="multipart/form-data" 이게 필수. 이게 자꾸 까먹힌다.
설정해놓고 보낸다음에 모델에서 이미 다 해놨다. uauth 모델에서 이미지 필드 미리 설정을 해놨다. profile = models....
오 파일이 오겠네? 파일은 media 유알엘에 저장. 그리고 저정된 경로를 여기서 텍스트로 가지고 있음.
지금은 이렇게 하고 나중에는 업로드한 파일ㅇ르 실제로 서버 컴퓨터에 저장하지 않고 s3같은 곳에 업로드한다. 내 서브 컴퓨터가 아니라 그쪽으로 저장한다. 그러면 url이 하나 나온다. 그러면 그걸 가지고 와서 db에 저장한다. 일단은 로컬컴퓨터에 저장하는 건 이렇게 하면 된다.
profile 정보가 없을 때 기본값 처리를 안해줘서 에러가 뜬 것.
이미지는 뜨는데 회원가입도 안 되고 그림 옆 아이디가 이상하게 나오기 시작했다..
잘 찍혀있는데..?
꺾쇠!!! 뺐다.
트랜잭션은 all or none이다.
지금같은 상황은 트랜잭션이 안돼있기 때문에 autocommit 되고 있다. db에 대해서 dml이 날라갈 때마다 커밋이 되고 있는 것. dml + tcl로 실제 완성이 된다. insert update delete를 하면 이거 자체만으로는 반영이 안돼서 이 뒤에 commit 이런 작업이 합쳐져야 실제 db 반영이 된다.
파이참 같은 클라이언트에 기본적으로 autocommit이 있어서 이걸 하나로 처리할 수 있었다. 하지만 자세히 보면 저게 따로따로이고, 트랜직션할 때만큼은 우리가 직접 해줘야 한다.
지금 상황은, user 모델 저장 오류 안 나면 커밋. userdetail 모델 저장 오류 안나면 커밋. 하는 상황이다. 그런데 만약 user 모델은 성공했는데 userdetail 저장하다가 값에 문제가 있다던가 실패했다. 그러면 지금 상황에서는 user 모델만 저장되고 userdetail은 저장이 안된다. 한번 직접 해보자.
테이블 우클릭 -> 테이블 수정 -> profile -> 기본값 varchar 100을 40으로 바꿨다.
여기 이미지 글자수보다는 커야 한다.
그러면 얼쓰 유저에는 아이디가 들어가고 얼쓰 유저 디테일에는 정보가 들어가지 않게 된다.
Django Transaction 처리
1. @transaction.atomic 함수 데코레이터 :
from django.db import transaction
아 이게 트랜젝션 오류다
위에꺼는 views.py에서 if form.is_vaild(): 호출 안해서 에러났던 거.. ()이거 추가하기.
더 추천하는 방법은
2. with transaction.atomic()
트랜잭션처리는 결국 sql에서 트랜잭션처리하라고 하면 어떻게 했냐면,
이렇게 했었다. 동시에 여러명의 클라이언트의 요청이 쏟아지고 있는 상황이라면, 이 안의 내용이 짧으면 짧을수록 유리하다. 그만큼 블락되는 시간이 짧아질테니까.
전체가 다 돼야 commit 중간에 하나라도 안되면 rollback
이렇게 해놓고 다시 테스트를 해보자.
아까처럼 에러가 나지만
두 곳 모두에 안 들어왔다.
파일 업로드는 왜 잘 될까?
여기서 이미 된거고, db 저장은 파일업로드와 별개라는 걸 알 수 있다.
2개 이상의 모델 클래스에 대한 DML 작업인 경우 반드시 사용
qna 앱에서 controller > question_views.py 에서 로그인된 사용자를 author로 등록해보자.
entity > models.py에서 확인해보면 여기 클래스 내용 중에 author에 할당해준 것을 확인할 수 있다.
repository.py에도 자동저장될것이 설정돼있다.
로그인하고 질문을 올려보자.
qna_question 테이블에 질문내역이 자동으로 들어온 것을 확인할 수 있다.
로그인 안하고 질문 올리면?
user 자리가 none은 아니고, 익명사용자 AnonymousUser로 채워져있다. 로그인 안 한 상태니까 이게 들어간 상태에서 Question.author에 원래 User 자리인데 거기에 AnonymousUser를 끼워넣으려는 상황이라 오류가 난 거다.
이게 바로 인가작업이 필요한 상황이라고 보면 된다. 로그인하지 않았다면 쓰기할 권한이 없는 거다. 이걸 하려면 검사를 해줘야 한다. 인증도 미리 돼있어야 하고, 인가(로그인한 사용자면 쓸 수 있게)를 인증으로써 판단해야 한다.
그래서 우리는 추가적으로 인가 관련 코드를 넣어주겠다.
from django.contrib.auth.decorators import login_required
로그인이 돼있으면 아래 코드 실행. 안돼있으면 uath:login으로 리다이렉트해라. 라는 명려어.
비로그인상태
로그인상태. 비로그인상태일 때 next 뒤에 써있던 내용이 바로 온다.
아이디가 뱃지처럼 author가 생겼다.
답변목록에도 생기게 해주자.
답변도 로그인된 사용자만 답변할 수 있게 해보자.
답변등록이라고 별도의 폼 페이지가 있는 게 아니라, question2라는 질문 페이지 안에 있는 구조다.
from django.contrib.auth.decorators import login_required
queston하고 왜 다를까
클라이언트, 서버가 있을 때
로그인 하지 않은 상태에서 get 방식의 퀘스쳔 크리에잍으로 들어가면 원래 홈페이지를 줘야하는데, 여기에 로그인 리쿼이어드를 우리가 넣었다. 그래서 야 로그인부터 해. 하면서 로그인 페이지로 이동시켜버린다. uauth/login 이렇게 리다이렉트.
그러면 로그인 폼 페이지를 받아낸다. (html) 이건 자동으로 처리됐다. (노란색 화살표)
여기에 추가적으로 html에 next=를 전달했다. 로그인 성공하ㅕㅁㄴ get 방식의 퀘스천 크리에잍으로 이동시켜줄게. 로그인해. 이렇게 되는 거. 로그인에 성공하면 포스트에 uauth/login 이렇게 해서 로그인에 성공했다고 치면 next 값으로 리다이렉트 하라고 나온다. 302/question/create 그러면 또 자동으로 노란색 화살표 리다이렉트가 되니까 처음에 했던 get /estueion create 해서 html form 페이지를 받는다.
이 흐름을 이해해야 한다.
로그인 reauired 덕분에 이런 흐름이 만들어졌다. 여기서 눈여겨볼 건 리다이렉트다. 리다이렉트는 무조건 get 방식이다. 근데 답변에 대해 그려보자.
답변은 이거랑 조금 다르다.
클라이언트, 서버
머물고 있는 페이지가 question/detail. 여기 있다가, 갑자기 POST/answer/create/쿼스천 번호(답변작성) 호출 여기서 login 리쿼이어드가 서버에서 기다리고 있음. 로그인 안 했으면 로그인 먼저 해. 302/uauth/login?next=/answer/create/퀘스천 번호 이렇게 가게 된다. 문제가 생겼다. 포스트에서 바디에 쓰여진 내용이 날라가고 유알엘만 따와서 주는 게 문제다.
그러면 302 리다이렉트 처리했으니까 get 방식으로 uauth login?next=answer/create/번호 이렇게 그대로 올거고, html (login form)을 클라이언트한테 주게 된다. 그러면 로그인 폼을 작성하고 로그인 요청을 날리게 된다. post/uauth/login 로그인에 성공하면 늘 리다이렉트 302/answer/create/123 이렇게 응답을 준다. 리다이렉트 하라고.
그러면 무조건 get/answer/create/123 이렇게 요청이 들어오게 되고 답변에 대한 등록이 필요한데 view는 이걸 바라는데 contetn가 없다. 그래서 이 오류를 만나게 된 거다.
애초에 로그인 하지 않았으면 맨 처음에 있는 Post 요청이 아예 안 오게 해줘야 한다. 로그인 하지 않은 자, 아예 처음부터 답변등록을 하지 못하게 하자.
비활성화 됐다. 그래도 답변등록 버튼은 눌린다.
그래서 ㅇ아예
에러 anonymous 오타
이렇게 확인창이 뜨게 하고
if(confirm('로그인이 필요합니다. 로그인페이지로 이동하시겠습니까?'))
확인 누르면 이동시킨다.
로그인하고 답변등록 버튼 클릭하면 계속 에러 남ㅎㅎ..
endif 뒤에 disable 넣었었음
이거 왜 한 거지..? 스크롤이 되고 있다?
강사님 결과화면
()
본인이 쓴 게시물에만 수정 삭제가 뜬다.
수정할 내용이 원래 화면으로 잘 따라온다.
인가확인
수정이 잘 되는 건 이미 한 거 아닌가? 여기서는 뭘 한거지..
현재는
편집된 것도 안 된 것도 다 편집됨이 나오고 있다.
created at 과 modified at 의 정보를 잘 보고 수정된 글만 '편집됨'이 나올 수 있게 해보자.
질문등록 질문수정 분기 구별
삭제
a 태그는 누르면 바로 이동이므로, 자바스크립트로 넘어가서 할 거다.
javascript:void(0)
자바스크립트 코드 말고 아무것도 안할래
data-로 시작하는 애들은 뒤에 오는 게 맘대로 작성하는 key 값이다. 태그에 데이터를 저장하는 용도로 쓴다.
data-url= url이라는 키값으로 삭제요청할 url을 적어두면 된다.
서비스
레파지토리
질문은?
서비스
리파지토리
에러
부트스트랩 모달
괴롭다.. 에러를 한참 해결했음.
뭘 고쳤는지도 모르겠다..
찾았다..
여기를 data-url이라고 써놨었음...ㅠㅠㅠㅠ
이제 삭제가 잘 된다.
그리고 모달 부트스트랩을 block 밖에 써놨었음.. 옮기니까 이제 답변 수정도 잘 된다.