Python 프레임워크, Flask(이론편)

Edwin·2023년 2월 12일
0
post-thumbnail
  • 본 글은 IML블로그를 기반으로 정리 요약된 내용입니다.
    IML블로그

Python 프레임워크, Flask(이론편)

pip install flask

프레임워크란?

워니, IT상식
프레임워크란? 개발을 돕는 역할을 수행하는 하나의 도구이다. 예를 들어서 요리를 간편하게 도와주는 밀키트 처럼 개발언어들을 쉽고 간편하게 조작할 수 있도록 만들어진 간편제공 서비스 정도로 여기면 좋을 것이다. 이를 통한 이점은 시간과 노력이 절약된다는 점이다. 프론트엔드에서 대표적인 프레임워크는 React이고, 백엔드에서 대표되는 프레임워크는 Spring, Django, Flask 등이 있다.

프레임워크와 라이브러리의 차이

라이브러리란 말그대로 도서관과 같이 해당 내용을 사용할 사용자가 취하고 싶은 것만을 가져가서 사용할 수 있는 단편기능이라고 본다면, 프레임워크는 특정한 틀 안에서 사전에 계획된 내용에서 벗어남 없이 움직여야 하는 패키지라는 측면에서 차이가 있다. 즉 전체적인 흐름을 제어하는 권한에 제한되는 프레임워크와 달리 라이브러리는 사용자가 직접 제어해야 한다는 점에서 약간의 차이가 있다.

01 Python Flask

파이썬을 기반으로 제작된 플라스트는, 웹개발 과정에서 특별한 도구나 라이브러리를 요구하지 않는다. 정말 간편하게 서버를 구축할 수 있다. 앞으로 자주 살펴보겠지만, 내용은 아래와 같다.

// 먼저, 가상환경을 위한 폴더를 생성해 준다. python -m venv venv
// 둘째, 터미널에서 프레임워크를 설치한다. pip install flask
// app.py [teplates] [static]  - 해당위치에 파이썬파일, 앞의 파일명을 가진 폴더를 만들어준다.
==============================
app.py
==============================

from flask import Flask
app = Flask(__name__)

@app.route('/')
def 함수명():
	return 'Hello, World'
    
if __name__ == '__main':
	app.run(debug = true)

먼저, 터미널에서 설치한 프레임워크를 해당 파일에 연결시켜준다.
둘째, @app.route('/')를 통해서 사용자가 작성한 HTML을 http://localhost:5000 에서 배포 할 때 경로를 만들어준다. 5000/ 세부경로(url)를 설정할 수 있다. return을 통해서 기록한 구문을 웹브라우저에 표시할 수도 있고, render_template('index.html')를 통하여 templates 폴더에 있는 해당 html 이름을 가진 파일을 실행시킬 수도 있으며, DB를 연결하는 등 특정한 방식에서 서버와 클라이언트 사이를 연결하여 정보를 주고 받을 때(jsonify)도 해당 구문으로 기록한다.
셋째, if구문은 app에 들어온 __name__을 실행할 때 로컬서버로 실행할 것을 선언하는 명령이다. 이어지는 debug = true 는 debug모드를 실행하겠다는 선언이다. debug모드란 웹 서버가 실행 중에 코드가 변경되어도 해당 작업을 그대로 반영시켜줄 것을 명령하는 구문이다. 즉 실시간으로 개발하는 내용의 변경 사항을 확인하며 작업할 수 있게 되었다는 것이다.

02 Python Flask 기초편 + Git ignore

오늘의 잔디와 .gitignore(깃추적에서 제외시키고 싶은 파일 목록리스트)

먼저 오늘의 잔디를 심을 준비를 함께 하면서 내용을 시작해보자.

어느 일상과 같이 오늘도 파일을 생성하고 가상환경을 설정해주었다. 그리고 git init 를 선언했는데, 커밋을 위해 working tree에 생성된 파일이 1300여개나 되었다(?). 보니 venv 파일에 생성된 파일들이었다. 해당 내용들이 git버전 관리에 추적되지 않도록 하고 싶을 때는 어떻게 해야할까? 바로 .gitignore 를 통해서 설정을 해주면 된다.

터미널에 아래와 같이 명령하자.

touch .gitignore

명령을 통해서 리눅스 touch 에디터에 의해서 빈파일 하나가 현재 진입된 폴더 최상단에 생성된다. 이렇게 생성된 .gitignore에 git의 추적을 피하고 싶은 파일의 목록들을 기록해 주면 된다.

그리고 터미널로 가서 git fetch 를 선언해보자. 그러면 커밋할 파일의 목록이 1300개에서, 내가 생성한 단 3개의 파일로 변경된 것을 볼 수 있다. 이와 같이 git의 추적을 피하고 싶은 파일의 목록들이 있다면, 해당 파일에 해당 파일.확장자폴더/를 기록해주면 된다.

파일을 원격저장소(github)과 연결하자. git init 로 생성된 메인브랜치에 해당될 main을 만들어준다. 그리고 원격저장소의 url을 통해서 연결해주고, 로컬저장소 main 브랜치를 원격저장소(origin)에 올려준다(push).

git branch -M main
git remote add origin https://github.com/githutName/repositoryName.git
git push -u origin main

이제야 git에 대한 부분이 이해되고 들어온다. 1) 로컬에 저장소를 생성하는 것(git init), 2) 생성된 버전에 main 브랜치를 생성하는 것(git branch -m main), 3) 원격저장소와 연결해주는 것(git remote add origin url, url은 https://github...) 4) 연결된 원격저장소와 로컬저장소를 연결을 위해, 로컬저장소의 main브랜치를 원격에 올려기(git push -u origin main). 이를 통해서 버전관리를 위한 준비가 끝났다. 본격적인 flask 공부로 들어가자.

URL 인자 사용하기

@app.route('/user/<username>')
def show_user_profile(username):
   return 'User %s' % username

함수를 읽어보자. 의의 코드에서 인자는 경로(url)에 있는 <username>이다. 이를 함수의 매개변수로 받을 수 있고, 이를 반환(return)하여 웹브라우저에 기록할 수 있다. 함수는 매개변수를 반환하여 "User %s"; 문자열(%s)로 반환하여 기록할 것이다. 주의할 점이 있다.

  • 인자에 기록한 /user/<username>
  • 매개변수에 기록한 username
  • 반환으로 기록한 % username

인자, 매개변수, 반환에 기록된 내용이 동일해야 한다는 점이다. username 말이다. 하나를 변경하면 3개를 함께 변환해야 한다. 이를 적용해 보자. 서버를 실행하고 웹브라우저로 가자. 가서 https:http://127.0.0.1:5000/user/아무거나 기록해보자.

위의 코드의 적용은 에디터가 아니라 실행된 웹브라우저이다. url경로에 직접입력을 해보라. 아무거나 입력해도 웹브라우저는 url에 기록된 내용을 웹브라우저 내용으로 가져온다. 이 부분에 대한 설명이 너무나 당연해서 그런지 기록되지 않아서 에디터에서 변경하고 오류나고를 20분 정도 헤맨 것 같다. 다시 느끼는 것은 구글링이 좋기는 하지만 친절한 설명은 많이 없다는 것을 느낀다. 주어와 술어의 부분에서 명확한 내용 보다는 기록의 의미가 많아서, 정확한 내용 전달이 되지 않아, 독자로 하여금 어려움을 느끼게 하기 때문이다. 위의 경우만 해도 정말 단순한 내용이었다. "코드로 기록했으면 웹브라우저의 url에 아무거나 입력해보아라"라는 설명이 있었으면 좋았지만 그러지 않았다.

이번에는 숫자로 기록된 url인자를 받아보자.

@app.route('/post/<int:post_id>')
def show_post(post_id):
    return 'Post %d' % post_id

웹브라우저로 가자 url, https://...5000/post/ 뒤에 먼저 문자를 입력해보자.



찾을 수 없다는 구문을 볼 수 있다. 왜냐하면, 위의 코드는 int(숫자)를 인자로 받는 코드인데 문자가 들어왔기 때문이다. 그렇다면 이번에는 숫자를 입력해보자.

인자의 값을 받고, 서버를 통해 반영할 때(return) 변수규칙이 존재한다는 것인데, strin(%s) 문자열, int(%d) 숫자열, float(%f) 소수점 등이 있다. 이때 특별한 언급을 하지 않으면 초기값으로 문자열을 인자를 전달한다.

만약에 경로 뒤에 값이 없다면? 초기값을 설정할 수 있을까? 아래와 같이 복수의 데코레이터를 입력함으로 초기값을 설정하는 것도 가능하다.

@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name="값이 비어있을 때 초기값 설정가능"):
  return 'User %s' %name


templates 폴더에 기록한 HTML문서 로컬에서 배포하기, render_template

from flask import Flask, render_template
app = Flask(__name__)

처음부분으로 올라가서 render_template를 추가해 주자. 이제 경로를 설정하고 반환(return)할 때, render_template를 통해서 처음에 설정한 templates 폴더 안에 기록한 html 파일을 로컬서버를 통해 웹브라우저에 배포하는 것이 가능해진다. 예를 들어서, 폴더 안에 study01.html 파일이 있고, 아래의 코드가 있다고 하자.

@app.route('/study01')
def study01():
  return render_template('study01.html')


(날아감...당황스럽다. 그래도 PDF 받아놓기를 다행, 복구하자.)

03 Redirec, HTTPS 메소드

flask가 동작중일 때에는 URL간의 이동(Redirect)이 가능한데, 이는 HTTP 메소드를 예를들어서 적용해보자.

1) Redirect

상황을 설정해 보자, 누군가 나의 웹브라우저에 방문했다. 로그인의 상황을 가정할 때 게스트와 유저에 따라서 다른 페이지로 이동시키고 싶다. 이럴 때 사용하는 것이, Rerdiect 이다. 사용 방법은 아래와 같다.

  • return redirect('/urlroute')
# 01 Redirect
from flask import Flask, redirect, url_for, request, render_template
app = Flask(__name__)

#redirect를 발생시킬 페이지
@app.route('/redirectpage/<name>')
def redirectpage(name):
  if name == 'guest':
    return redirect('/guest')
  else:
    return redirect(url_for('hello_user', username = name))
    
#상황1 - 방문자일 때, guest 일 때
@app.route('/guest')
def hello_guest():
  return '안녕 redirect 알아보기, 방문자님 안녕하세요.'

#상황2 - 사용자일 때, guest 이외일 때
@app.route('/user/<username>')
def hello_user(username):
  return '안녕 redirect 알아보기, %s님 반갑습니다.' % username      
사용법(1) 메소드 호출
  • import Flask, redirect, url_for

첫줄에 import 부분에 flask프레임워크에 속한 라이브러리들을 입력해 준다. redirect는 경로를 반환해주고, url_for 는 함수를 반환해 준다.

사용법(2) redirect 상황 만들기
#redirect를 발생시킬 페이지
@app.route('/redirectpage/<name>')
def redirectpage(name):
  if name == 'guest':
    return redirect('/guest')
  else:
    return redirect(url_for('hello_user', username = name))

상황을 발생시킬 인자(<name>)을 매개변수로 담고, 그 조건에 따라서 두 가지의 경로를 설정해 준다. 만약 <name> 가 guest이면, redirect('/guest') 경로로 연결시키고, guest 이외일 때(user) redirect(url_for('hello_user', username = name)) 함수를 호출하고, 인자(<name>)로 들어온 name을 함수의 인자로 돌려서 반환(return)해 준다.

사용법(3), guest 일 때
#상황1 - 방문자일 때, guest 일 때
@app.route('/guest')
def hello_guest():
  return '안녕 redirect 알아보기, 방문자님 안녕하세요.'

상황1의 내용에 따라서 반환된(return redirect) 경로의 내용이 실행된다.

사용법(4), guest 이외의 상황(사용자일 때)
#상황2 - 사용자일 때, guest 이외일 때
@app.route('/user/<username>')
def hello_user(username):
  return '안녕 redirect 알아보기, %s님 반갑습니다.' % username  

@app.route('/redirectpage/<name>' 에 선언된 인자가
@app.route('/user/<username>')에 username으로 전달되고, 그 인자의 값이 URL인자 사용하기에 따라서 '안녕 redirect 알아보기, %s님 반갑습니다.'의 값으로 선언될 것이다.

사용법(5), 전체코드 활용하기

위의 코드로 실행된 웹브라우저에서 테스트를 해보자. 아래의 url을 입력해보자.

2) HTTP 메소드

from flask import Flask, redirect, url_for, request, render_template
app = Flask(__name__)

이번에는 request 를 불러와야 한다. 이제 코드를 살펴보자. 여기서 실행시킨 request는 pip에서 설치해줘야 하는 request 라이브러리와 같은 기능을 한다. 그러나 설치해줄 필요가 없는데, 이는 flask프레임워크가 해당 내용을 내장하고 있기 때문이다. 그러기에 단지 불러오기만 하면 된다.

# 02 HTTP 메소드 이론편
#상황발생 : HTTP메소드를 실행시킬 조건의 상황 설정
@app.route('/login',methods = ['POST', 'GET'])
def login():
   if request.method == 'POST':
      user = request.form['nm']
      return redirect(url_for('success',name = user))
   else:
      user = request.args.get('nm')
      return redirect(url_for('success',name = user))
    
#발생상황 : 조건부 상황에 따라 실행될 결과적 경로
@app.route('/success/<name>')
def success(name):
   return '반갑습니다. %s님' % name
사용법(1), methods 방식에 따른 설정

@app.route('/login',methods = ['POST', 'GET']) login 경로에 접근하는 두가지 메소드 방식이 선언되었다. 하나의 방법은 POST(수정/변경/삭제)가 발생되었을 때에고, 다른 하나의 방법은 GET(조회)이 발생되었을 때이다.

사용법(2), methods=['POST'] HTML 문서의 내용
  • HTML 문서의 내용
<html>
   <body> 
      <form action = "http://localhost:5000/login" method = "post">
         <p>이름을 입력하세요:</p>
         <p><input type = "text" name = "nm" /></p>
         <p><input type = "submit" value = "이름입력" /></p>
      </form>
      
   </body>
</html>

<form>태그 로 입력된 내용이 app.py에 기록된 경로로 전달(http://localhost:5000/login)된다.
request.form['nm'] 요청된 웹브라우저로부터 'nm'의 값이 user라는 변수에 대입되고,
url_for('success') 로 redirect를 실행할 때, 웹브라우저로부터 받은 'nm' -> user -> name을 가지고 간다.
해당 결과에 따라 실행된 /success는 이전 경로로부터 전달된 인자(name)를 매개변수로 가져와서, 설정된 내용을 반환(return)해 준다.


이름입력하기 버튼은 클릭 또는 엔터를 처보자. 그러면 해당 속성의 name에 해당 내용이 변수로 담겨서, 서버로 전달된다. 그리고 그 nm(에 담긴 사용자로부터 받은 정보)이 결과적으로 success 경로의 인자로 담겨져서 결과페이지에 아래와 같이 기록될 것이다.


사용법(3), methods=['GET']
POST 방식은 이해가 된다. 그런데 여기서 말하는 GET은 어떤 것일까? Jquery의 ajax을 통해서 methods를 설정했을 때는 내용을 전달하는 것이 아니라, 단지 서버에 있는 값을 요청할 때에만 사용했던 방식이었다. 그래서 이 부분에서 말하는 GET이 어떤 방식으로 작동되는지에 대해서는 찾아봐야겠다.

그래도 힌트가 있다. request.args.get 부터 찾아보자. form과 다른 속성이기 때문이다. 이를
이해하기 위해서는 API에 대해서 알아야 하는데 아래와 같다.

자바스크립트의 객체와 파이썬 딕셔너리는 서로 닮았다. {중괄호} 안에 key:value 를 가진다. 또한 flask에 내장된 request는 pip을 통해서 설치해야 하는 requests라이브러리와 동일한 역할을 flask에서 실행하는데, 이를 이해하기 위해서는 requests라이브러리의 소통방식을 이해할 필요가 있다.

  • requests.get('사이트주소')
    클라이언트에서 서버에 요청(request)되면, 결과가 응답(response) 되어 돌아간다. 이때 클라이언트와 서버의 소통은 json 파일을 통해서 주고 받게 된다. 만약 이를 프레임워크가 아니라 라이브러리도 사용한다면, pip install jsonify 도 해주어야 할 것이다. 클라이언트와 서버는 json 데이터로 변환된 내용을 서로 읽고 그에 따라 자신이 해야할 일을 각각 수행한다.
  • requests 라이브러리를 통해서 전달된 정보(서버쪽)

    request.get_json('key')
    app.py에서는 위의 명령어로 클라이언트에서 전달된 내용을 볼 수 있게 된다.

-flask프레임워크 request

request.args.get('key')
위의 라이브러리와 동일한 기능을 수행하는 Flask프레임워크 구문이 위의 소스코드이다.

IML블로그에서 기록한 것과 같이 url에 바로 입력을 시도했다. 그런데 Not Found가 발생되었다. 일단 현재에서는 구글링을 해도 잘 모르겠다.

author.EDWIN
date.23/02/13 AM 02:33, AM 07:03(수정)

profile
신학전공자의 개발자 도전기!!

0개의 댓글