[수업 3째주 8일차] Python-3

김유민·2022년 3월 31일
0

대구 A.I. 스쿨

목록 보기
6/90

1. 학습내용

Flask를 어제에 이어 계속 배워나갔다.
전체 주석은 윈도우 기준 Ctrl+/이다.

어제 flask를 이용해서 링크를 걸면 제목과 내용이 바뀌는 것과, 제목과 내용을 넣어 제출을 누르면 되는 폼까지 완성했다.

오늘은 폼에 내용을 넣으면 화면에 추가로 표시되게 끔 하는 것을 배웠다.

@app.route('/create_process/', methods=['POST'])
def create_process():
  global nextId
  title = request.form['title']
  body = request.form['body']
  newTopic = {"id":nextId, "title": title, "body": body}
  topics.append(newTopic) #topic도 함수가 밖에 있지만 수정이 아닌 값을 추가하는거라 global을 쓰지않음
  nextId = nextId + 1
  return redirect(f'/read/{nextId-1}/')

정확히 어제 배운건 제목과 본문을 입력하면 웹 주소 뒤에 추가가 되게 끔 적었다.
그러나 그렇게 노출이되어 적히면 보안상의 문제가 발생할수 있다.
보통은 서버에 내용을 전송하는 방식이 http프로토콜 상에서는 GET과 POST방식이 있는데,
아이디나 비밀번호 같은 민감한 정보들은 유출이 될 수 있기 떼문에 메소드를 POST로 바꿔준다.
그래서 기존 폼의 form태그에 method="POST"라고 추가한다.

@app.route("/create/")  
def create(): #아무이름도 상관없음.
  content = '''
 <form action="/create_process/" method="POST"> <!--method를 post로 바꾼것. 일반적으로 get으로 전송됨-->
      <p><input type="text" name="title" placeholder="title"></p>
      <p><textarea name="body" placeholer="body"></textarea></p>
      <p><input type="submit" value="create"></p>
    </form>  
  '''
  return template(content)

그리고 받는 쪽 라우터에도 post라고 설정하지 않으면 에러가 난다. 받는 쪽을 새로 만들어 위에서 말했던 '기존의 본문에 입력한 데로 추가하는' 라우터를 추가해 보자.

@app.route('/create_process/', methods=['POST'])

:참고로 POST나 GET은 대문자로 써야 한다.

뒤에는 def를 적고 임시로 return을 입력해 화면에 값이 나타나는지 확인한다.
위의 input값을 받았는지 안받았는지 확인하기 위해서이다.

def create_process():
	return 'success!'

값이 잘 나오면 새로 생긴 라우터에 대체 무슨 값을 받는지를 써줘야 하는데, POST방식으로 된것을 Flask프로세서에서 쓸려면 request 방식으로 쓰라고 되어 있다.
Flask request 방는 방법 : https://flask.palletsprojects.com/en/2.1.x/quickstart/#the-request-object

그리고 저걸 쓸려면 맨 상단에 import 부분에 'request'라고 추가해 주어야 한다.

from flask import Flask, request
.
.
.
def create_process():
	title = request.form['title'] #일단 제목만 출력해보았다.
	return title

본문값도 추가하고 싶다면 제목처럼 추가해주면 된다.

body = request.form['body']

그렇게 폼에다 쓴 제목과 내용을 앞서 topics에 디렉토리에 적힌 내용에 추가하는 방식으로 추가한다고 해야 우리가 하기로한 기존의 1.html,2.css,3.js의 목록 뒤에 추가해서 웹상에 보여질 수 있게된다.
일단 newTopic이라고 새로운 딕셔너리를 def create_process():밑에 우리가 적었던 request아래에다 적는다.

newTopic = {"id":?, "title": title, "body": body} #id는 일단 뭐가 들어갈지 몰라 ?표시로 둠.

딕셔너리에 request로 지정한 변수들(title,body)를 적어준다.
그런다음, 이제 저 ?부분을 채워야 한다. 3개의 목록 뒤에 추가되는 것이기 때문에, 처음의 id를 뭘로 설정할까를 일단 정해서 시작하게끔 해야한다. 방법은 여러가지가 있지만 강사분 께서 제시하신 방법은 다음과 같다.
먼저 3개 이후에 오기 때문에 맨 밖에 nextId라는 새로운 변수를 만든다.

nextId = 4 #4라 지은 이유는 마지막에 적힌 id가 3이기 때문에.

그런다음 ?를 nextId라고 적고 newTopic다음줄에 nextId다음에 새로 올 항목이 생긴다 해서

nextId = nextId + 1

이라고 적어준다. 그러니까 다음에 채울 공간을 미리 만들어 주는거다.
그다음 nextId와 newTopic사이에 topics에 목록을 추가해 넣어 준다는 식을 적는다.

topics.append(newTopic) #newTopic을 추가한다는 의미.

그런데 nextId = nextId + 1 는 nextId를 수정하는 식인데, nextId는 현재 식의 밖에 쓰여진 함수다. 밖에 쓰인 함수는 수정이 불가하다. 그러면 어떻게 해야 할까? 그럴땐 함수 안에서
밖에 쓰인 함수라고 global이라 정의해준다.

global nextId

그런데 topics도 append 라고 해서 추가하는건데 왜 global을 안쓸까? 이유는 아예 수정이 아닌 기존의 내용에서 추가만 되는거라 굳이 쓰지않는다.

그래서 저렇게 title과 body를 받았다. 그럼 저걸 받았다고 알수 있게 보여질려면 어떻게 해야 할까?
return 값에 임의로 'success'라 출력되게 하고 저게 출력되는 화면으로 넘어가게 끔 'go!(적힌page)' 로 적을거다.
적힌 페이지는 아마도 /read/가 될건 알겠는데 id 숫자는 어디로 가게 적어야 할까? 그건 nextId로 정의해준 page로 가게 하면 된다.
만약 3뒤에 '4.추가된 내용'으로 가고 싶다면 '/read/nextId-1'라고 해주면 된다.
왜냐하면 우리가 앞서 자동으로 다음 공간이 생기게 +1을 했기 때문에 원래 공간의 페이지로 보여지게끔 하려면 -1을 해야 하기 때문이다. 그래서 올바른 선언을 f~string으로 쓰면 아래와 같다.


@app.route('/create_process/', methods=['POST'])
def create_process():
  global nextId
  title = request.form['title']
  body = request.form['body']
  newTopic = {"id":nextId, "title": title, "body": body}
  topics.append(newTopic) #topic도 함수가 밖에 있지만 수정이 아닌 값을 추가하는거라 global을 쓰지않음
  nextId = nextId + 1
  return f'Success! go:/read/{nextId-1}/'

이렇게 하면 빈화면 상단에 Success! go /read/4 뭐 이런식으로 뜰거다. 그런데 일일히 사용자더러 저걸 복사해서 주소창에 붙여넣기 해서 가라고 할수는 없으니, 원래 화면으로 돌아가게끔 하려면 redirect해야 한다.
redirect도 import에 추가해 적어 준 후에 식을 적어주어야 한다.
새로 추가되는 여기서는 '4.내용'이 추가되기 때문에 저 페이지로 넘어가게 하는 기능을 redirect라고 한다.

@app.route('/create_process/', methods=['POST'])
def create_process():
  global nextId
  title = request.form['title']
  body = request.form['body']
  newTopic = {"id":nextId, "title": title, "body": body}
  topics.append(newTopic) #topic도 함수가 밖에 있지만 수정이 아닌 값을 추가하는거라 global을 쓰지않음
  nextId = nextId + 1
  return redirect(f'/read/{nextId-1}/')

그럼 내용이 추가된 페이지가 뜨면서 본문과 제목도 추가된 내용으로 바뀌어 출력된다.

+추가로 데이터베이스에 관련된 내용을 배웠다. 여러 데이터베이스 프로그램 중에 우리가 배운건
SQlite3로 이걸 깔아서 표를 만들고 열과 행을 추가하는 걸 배웠는데, 수업 내용이 초과가 되어 내일 배운 내용과 합쳐서 올리려 한다.

2. 어려웠던 점 및 해결 방안

뒤에선 '삭제'에 해당하는 내용을 배웠다. (생성, 읽기, 수정, 삭제 중 수정은 시간이 모자라 못배움)
일단 버튼을 생성해 버튼을 누르면 목록중 선택한 내용이 삭제되는 기능이 있는 코드를 작성하기로 했다.
우선 template함수에 버튼을 추가할 form태그를 작성한다.

<li>
 <form action="/delete/{id}/" method="POST">
   <input type="submit" value="delete">
 </form>
</li>

여기까진 했고, 이 다음 delete의 라우터를 추가하는 것 까진 했다.

@app.route('/delete/<int:id>/', methods = ['POST']) #수령받는 메소드는 여러개일 수 있어서(get이나 post나 그래서복수형인 's'가 들어간다.
def delete():

근데 여기 이후 부터는 어떻게 식을 작성해야 하는지를 모르겠어서 다시 강의를 보기로 했다.
일단 delete()에서 괄호안에 반드시 id가 적혀 있어야 한다.
id가 변하는 값이기 때문에 변수를 적어 해당값이 들어오면 아래의 함수를 실행해야 되기 때문이다.
그리고 <int:id>라고 인트라 정의하고 숫자라 선언했기때문에 문자로 출력되기 위해
return 값에 str(id)라고 써줘야 한다.
그럼 해당되는 아이디의 숫자가 출력된다.
/delete/1이런페이지 주소라면 1만 출력된다는 소리다.
그럼 지우는 기능을 넣고 싶다면 어떻게 해야 할까. topics의 아이디 값이 선택한 사이트의 값과 일치하면 지운다는 뜻이고, 그걸 반복한다는 뜻에서 for문을 쓴다.

  for topic in topics:
    if topic['id'] == id:

왜 반복문을 쓰는지 몰랐는데, topics에 있는 자료들을 누를때 마다 다른 것일꺼기 때문에 쓰는 것으로 이해했다.
그래서 삭제는 remove니까 적용할려면 이렇게 써야 한다고.

topics.remove(topic) #topics안에 해당 topic 내용이 있으면 관련 내용 전체를 삭제한다는 의미.

그래서 뒤에 반복문이기 때문에 break;를 추가하고 return만 다시 쓰면 된다.
삭제는 우리가 삭제되었다는 것을 당장 확인할 수 없기때문에 기존의 화면으로 돌아가는
redirect를 쓰고 홈화면인 '/'라고 뒤에 추가하면 된다.

@app.route('/delete/<int:id>/', methods = ['POST'])
def delete(id):
  for topic in topics:
    if topic['id'] == id:
      topics.remove(topic)
      break;
  return redirect('/')

3. 학습소감

앞으로 점점 전날 내용을 이해해 두지 않으면 배워나가기 힘들겠다는 생각을 했다.
어제의 연장선이긴 했지만 새로운 명령어가 나올때 마다 혼란스럽지만, 그만큼 신기했다.
여전히 함수를 혼자 쓰라하면 다는 못쓰지만 한줄 정도는 위에것을 보고 배껴적을 정도는 되었다는 생각에 조금 뿌듯함을 느꼈다.

profile
친숙한 개발자가 되고픈 사람

0개의 댓글