[수업 3째주 7일차] Python-2

김유민·2022년 3월 30일
0

대구 A.I. 스쿨

목록 보기
5/90

1. 학습내용

flask에 대해 알아보았다.
flask란?
웹 애플리케이션 개발을 위한 파이썬 프레임워크다.
물론 여러 프레임워크가 있지만, flask가 다른 프레임워크에 비해 가볍고 입문자들이 쓰기엔 그나마 편하다고 한다.

우선 어제의 pandas처럼 터미널을 열어 'pip install flask'라고 하면 바로 설치가 된다.
하지만 컴퓨터마다 환경이 다르고, 잘 설치되지 않는 사람들이 있을 수 있어 이걸 제공하는 사이트를 대체해서 사용하기로 했다.

사이트주소: glitch.com
여기에서 회원가입을 하고 검색에 'flask'를 치면 바로 상단에 뜨는데 그걸 눌러서
예제 코드 화면을 띄울수 있다.
거기서 원래 있던 코드를 지우고 새로 코드를 짜면된다.

일단, 이 flask를 이용해 웹에서 html형식으로 보여지게 만들 수 있다.
즉 웹브라우저는 이걸 사람이 작성하면 html형식으로 변환된 걸 받는데 그럼 사람이 아닌 기계가 한걸로 인식해 화면상에 보여주게 된다.
예제로, 'Hello World'라고 화면에 띄우게 해보자.

from flask import Flask #플라스크 프레임워크를 불러온다는 의미.
app = Flask(__name__)

@app.route('/')
def hello_world(): #어제 배웠던 함수식 처럼 임의로 적은 아이디 같은것.
    return 'Hello, World!'
app.run()   

이렇게 쓰면, 바로 Hello, World!라고 화면상에 출력된 것을 알수 있다.

다른 예제로 만약 랜덤한 숫자를 나타내고 싶다면 이렇게 쓴다.

from flask import Flask
app = Flask(__name__)
import random

@app.route("/")
def index():
  return random.random()

app.run()

근데 이렇게 하면 화면에 에러가 뜬다 여기서 logs를 보면 왜 안되는지 알 수 있는데
이럴땐 random.random()을 숫자로 변경한다는 의미로 str로 감싸준다.


from flask import Flask
app = Flask(__name__)
import random

@app.route("/")
def index():
  return str(random.random())

app.run()

그럼 새로고침할때 마다 랜덤한 소수가 나온다.

여기에 'random'이란 문자를 붙이고 싶다면 어제 배운 것들을 응용해 넣을 수 있다.


from flask import Flask
app = Flask(__name__)
import random

@app.route("/")
def hello_world():
  return '<strong>random</strong> : '+str(random.random())

app.run()

그럼 저 'random'이란 글자 부분이 굵게 처리된다.

여기서 저 route부분이 궁금한데 라우트는 외부 웹브라우저에서 웹서버로 접근시 해당서버로 접근하면 route밑의 함수 부분이 실행되게 해주는 코드이다.
그러니까 저기 '/'에서 /뒤에 공란이면 메인페이지로, /에 예를 들어 '/create/'라고 적으면 새 페이지에서 그 아래의 함수를 실행시켜준다는 의미이다.

@app.route("/create/")
def create():
  return 'create'

로 적으면 메인주소에서 뒤에 /create/만 추가 해주면 create라고 페이지에 출력된 것을 알 수 있다.

저 return 뒤에는 따로 html을 적어서 출력시킬 수도 있다.

@app.route("/")
def index():
  return '''
  <html>
    <body>
      <h1><a href="/">html</a></h1>
      <ol>
        <li><a href="/read/1/">html</a></li>
        <li><a href="/read/2/">css</a></li>
        <li><a href="/read/3/">js</a></li>
      </ol>
      <h2>Welcome</h2>
      Hello, WEB!
    </body>
  </html>
  '''

그런데 위의 a태그에 /read/1/을 받아내고 싶다면 따로 또 작성해 주어야 한다.

@app.route("/read/1/")
def read():
  return '''
  <html>
    <body>
      <h1><a href="/">html</a></h1>
      <ol>
        <li><a href="/read/1/">html</a></li>
        <li><a href="/read/2/">css</a></li>
        <li><a href="/read/3/">js</a></li>
      </ol>
       READ
    </body>
  </html>  
  '''

&주의할 점은 def이후로 들여쓰기를 잘 못하면 값이 에러가 나거나 실행이 안된다.

그런데 저 ol태그가 중복되어 보인다. 웬만해서 줄여 쓰는게 좋으니 저걸 어제 배운 배열로 통해 줄여서 써보기로 한다.

topics = [
  {"id":1, "title":"html", "body":"html is ...."},
  {"id":2, "title":"css", "body":"css is ...."},
  {"id":3, "title":"js", "body":"js is ...."},
]

이렇게 2차원 방식으로 나열하면 중복된 부분을 짧게 줄여써야 한다. 그럴때는 for문을 써준다.
일단 js의 변수처럼 선언을 먼저 해준다. 여기서는 liTags라고 선언을 해보자.

topics = [
  {"id":1, "title":"html", "body":"html is ...."},
  {"id":2, "title":"css", "body":"css is ...."},
  {"id":3, "title":"js", "body":"js is ...."},
]

@app.route("/")
def index():
  liTags = ''
  for topic in topics:
    liTags = f'<li>{topic["title"]}</li>'
  return f'''  #f-string을 써서 liTag를 대입한다는 의미로 f를 써준다. 파이썬3이후버전만가능
  <html>
    <body>
      <h1><a href="/">html</a></h1>
      <ol>
        {liTags}
      </ol>
      <h2>Welcome</h2>
      Hello, WEB!
    </body>
  </html>
  '''

그런데 이렇게 하면 마지막 js만 출력되는데 이유는 for는 '~동안' 이란 뜻으로 언제까지 로드할건지 정해주지 않으면 마지막걸로 덮어쓰기 해서 출력된다. 그래서 다 출력되게 하고 싶다면,
기존의 liTags를 더해줘야 한다. 아래 방식으로 적으면 된다.

topics = [
  {"id":1, "title":"html", "body":"html is ...."},
  {"id":2, "title":"css", "body":"css is ...."},
  {"id":3, "title":"js", "body":"js is ...."},
]

@app.route("/")
def index():
  liTags = ''
  for topic in topics:
    liTags = liTags + f'<li>{topic["title"]}</li>'
  return f'''
  <html>
    <body>
      <h1><a href="/">html</a></h1>
      <ol>
        {liTags}
      </ol>
      <h2>Welcome</h2>
      Hello, WEB!
    </body>
  </html>
  '''

liTags에서 생성된 f~이후 것들이 계속 만들어지고 기존 liTags에 더해지면서(+)쌓이는 방식이라 할수 있다.
여기다가 앞에서 'a'태그로 링크걸어주는 거 까지 해주면 아까와 그대로 표시된다.

@app.route("/")
def index():
  liTags = ''
  for topic in topics:
    liTags = liTags + f'<li><a href="/read/{topic["id"]}/">{topic["title"]}</a></li>'
  return f'''
  <html>
    <body>
      <h1><a href="/">html</a></h1>
      <ol>
        {liTags}
      </ol>
      <h2>Welcome</h2>
      Hello, WEB!
    </body>
  </html>
  '''

그런데 여기서 화면상에 css를 누르면 /read/2/가 없기 때문에 출력이 안된다.
그래서 /read/1/걸 복사해서 (def값 바꿔야 한다) 하면 출력이야 되지만 여러개의 라우터를 똑같은걸 계속 복사하면 코드도 길어지고 효율적이지 않다. 그렇기에 하나만 적어주려 한다.
그럴때는 /read/뒤에 가변적으로 바뀐다고 해서 아이디를 부여 한다. 여기선 'id'라 적겠다.

@app.route("/read/<id>/")
def read(id):
  print(id)
  return '''
  <html>
    <body>
      <h1><a href="/">html</a></h1>
      <ol>
        <li><a href="/read/1/">html</a></li>
        <li><a href="/read/2/">css</a></li>
        <li><a href="/read/3/">js</a></li>
      </ol>
       <h2>Read</h2>
      Hello, Read!
    </body>
  </html>  
  '''

여기에서 id가 확실히 적용되는지 알려면 def 밑줄에 print를 적어 로그에서 확인해보면 된다.

그런데 위의 딕셔너리에서 정한 'id'처럼 숫자로 /read/뒤에 넣고 싶다. 그러면 정수로 바꿔주겠다라고 int를 쓰고 감싸준다.

@app.route("/read/<int:id>/")
def read(id):
  return '''
  <html>
    <body>
      <h1><a href="/">html</a></h1>
      <ol>
        <li><a href="/read/1/">html</a></li>
        <li><a href="/read/2/">css</a></li>
        <li><a href="/read/3/">js</a></li>
      </ol>
       <h2>Read</h2>
      Hello, Read!
    </body>
  </html>  
  '''

다음은 제목과 내용을 딕셔너리에 맞춰서 각 링크를 눌렀을때 변경하고 싶다면 아까처럼 for문을 써서 변경해준다.

@app.route("/read/<int:id>/")
def read(id):
  title = ''
  body = ''
  for topic in topics:
    if topic['id'] == id:
      title = topic['title']
      body = topic['body']
      break;
    
  return f'''
  <html>
    <body>
      <h1><a href="/">html</a></h1>
      <ol>
        <li><a href="/read/1/">html</a></li>
        <li><a href="/read/2/">css</a></li>
        <li><a href="/read/3/">js</a></li>
      </ol>
       <h2>{title}</h2>
      {body}
    </body>
  </html>  
  '''

if문을 넣어 id값이 딕셔너리의 id값이 일치할때, title과 body값이 출력되게 하고, 위에 title과 body값을 초기화 시켜서 = ''라고 적는다.
아래엔 f -string넣고 title 적고 body 적으면 된다.

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

마지막에 코드를 중복해서 적는게 아닌 줄여서 적는게 어려웠다. 다시 동영상을 보고 응용하는 법이 아직 어려웠는데.
마지막 부분 특히 js에서 foundation에 해당되는 부분이 어려웠다.
그러니까 위에서 index부분의 html과 read부분의 html 부분이 똑같다. 그래서 함수를 따로 만들어주고 그 함수를 적어준다.

def template(): #항상 ()뒤에 :을 적어준다.
  liTags = ''
  for topic in topics:
    liTags = liTags + f'<li><a href="/read/{topic["id"]}/">{topic["title"]}</a></li>'
  return f'''
  <html>
    <body>
      <h1><a href="/">html</a></h1>
      <ol>
        {liTags}
      </ol>
      <h2>Welcome</h2>
      Hello, WEB!
    </body>
  </html>
  '''
  

@app.route("/")
def index():
  return template()

여기까진 이해가 됬는데, 실행이 안되는 부분도 고쳤고, 그런데 다음에 /read/<>/부분에도 똑같이 하려니 title과 body 부분이 달라서 따로 뭘 적어줘야 한다. 그래서 다시 동영상을 보고 체크를 해보니까 '파라미터'를 함수괄호 안에 따로 줘야 했다.
먼저 index에 template괄호 안에 링크를 다른 걸 누를때 마다 title과 body가 바뀌는 기존

'<h2>welcome</h2>Hello,WEB!'

내용을 넣어준다.
그리고 정작 바뀌는 부분인 /read/부분엔 저 welcome~부분을 {title}과 {body}라고 바꾼다음(f ~string 넣어야 한다.)
함수를 설정한 부분으로 돌아가 함수()괄호 안에 임의의 이름인 'content'를 넣으면 누를때 마다 제목과 본문이 바뀌는 것을 확인 할수 있다.

def template(content):
  liTags = ''
  for topic in topics:
    liTags = liTags + f'<li><a href="/read/{topic["id"]}/">{topic["title"]}</a></li>'
  return f'''
  <html>
    <body>
      <h1><a href="/">WEB</a></h1>
      <ol>
        {liTags}
      </ol>
      {content}
     <ul>
       <li><a href="/create/">create</a></li>
     </ul>
    </body>
  </html>
  '''
@app.route("/")
def index():
  return template('<h2>Welcome</h2>Hello, WEB!')

@app.route("/read/<int:id>/")
def read(id):
  title = ''
  body = ''
  for topic in topics:
    if topic['id'] == id:
      title = topic['title']
      body = topic['body']
      break;
  return template(f'<h2>{title}</h2>{body}')

+참고로 저 바꾸고자 하는 제목과 본문에 해당되는 값을 'content'라 지정해 주었으면, 만든 함수인 'template'에서 기존에 적힌 제목과 본문을 지우고 {content}라고 적어야 적용된다.

++ 추가로 배운 내용
입력 폼을 만들어 구글 검색기능에 연동 시킬 수도 있다.
먼저 template함수에 폼을 넣을 부분을 ul태그를 넣어주고, 검색기능이 들어갈 부분을 'create'라고 따로 만들어 본문 내용을 넣는다.

#template에 넣을 부분
      <ul>
       <li><a href="/create/">create</a></li>
     </ul>
 #따로  'create' 넣은 부분
 
@app.route("/create/")
def create():
  content = '''
    <form action="https://www.google.com/search">
      <p><input type="text" name="q" placeholder="title"></p>
      <p><textarea placeholder="body"></textarea></p>
      <p><input type="submit" value="create"></p>
    </form>
    '''
  return template(content)

html을 넣어 form태그 안에 input태그와 내용이 들어갈 textatea부분을 넣는다.
구글 검색을 끌어오고 싶으면 form에 action을 적고 검색이되는 사이트 주소를 넣는다.
주소가 길게되면 &뒤에 파라미터(입력값)이 붙는데 보통 검색을 하고 싶은게 html이면
넣을 테그에 name을 적고 "q"라 적으면 적은내용이 바로 구글에 검색되어 나온다.

3. 학습소감

점점 더 어려워지는 수업내용에 오늘따라 더 정신을 차리기 힘들었다.
특히 비쥬얼스튜디오코드처럼 자동완성이 되는게 아니라서 타자가 느린 나에겐 수업따라가는게
꽤 힘들었다. 다시 동영상을 봐야지 이해가 갔고, 마지막 제목과 본문을 링크를 누를때마다 변경하는 것은 다시 봐도 완전한 이해가 어려웠다. 그래도 수업때 이해도가 30%였다면, 복습을 했을때는 65~70%정도로 이해가 올라갔으니..
동영상 녹화본이 있어 얼마나 다행인지 모른다. 앞으로도 열심히 복습해 나간다면 더 좋은 결과가 있을거라 기대해본다.

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

0개의 댓글