항해 99

Flask 맛보기

iksadnorth 2023. 8. 5. 15:44

👣 개요

웹 개발의 전체적인 흐름을 파악하기 위한 Flask 지식 공부.

 

👣 대략적인 프로젝트 구조

📦Root
 ┣ 📂static
 ┃ ┃ 📜image.png
 ┃ ┃ 📜script.js
 ┃ ┗ 📜style.css
 ┣ 📂templates
 ┃ ┗ 📜index.html
 ┗ 📜app.py

static
CSS, JS, 이미지 등등의 정적 파일을 보관하는 곳.

templates
Jinja2 템플릿 파일을 보관하는 곳.

app.py
Flask 애플리케이션을 정의하고 구성하는 데 사용되는 파일.

 

👣 라이브러리 구성

pip install flask dnspython

참고로 dnspython은 DNS 프로토콜을 Python에서 다루기 위한 라이브러리.

 

👣 대략적인 app.py 구성

from flask import Flask, render_template

app = Flask(__name__)

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

@app.route("/call", methods=["POST"])
def post():
    return 'This is the about page.'

if __name__ == '__main__':
   app.run('0.0.0.0', port=5000, debug=True)
app = Flask(__name__)

해당 코드는 Flask를 이용하기 위한 Flask 객체를 만드는 과정이다.
__name__은 현재 모듈의 이름을 뜻하며,
이것을 Flask 객체에 넘겨줌으로서 해당 어플리케이션의 루트 경로를 정의한다.

@app.route('/')

해당 명령어는 라우팅(route)을 처리하기 위한 데코레이터다.
쉽게 말해 http://localhost/home으로 요청했는지 http://localhost/memo으로 요청했는지를 
판단하고 그에 맞춰 처리를 하기 위한 장치라고 볼 수 있다.
위 명령어는 http://localhost/ 로 요청 시, 해당 데코레이터가 지정한 메소드로 처리하겠다라는 의미다.

해당 데코레이터로 지정한 메소드의 Return값이 주로 응답의 Body의 내용을 구성하게 되는데 
이에 대한 깊은 이해는 다음 항목에서 다룰 예정이다.

if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)

해당 명령줄은 실질적으로 서버의 구동을 선언하는 명령어들이다.
app.run을 호출하게 되면 그제서야 설정해준 내용들을 토대로 구동이 된다.
debug = True로 설정하면, 디버그 모드가 활성되고 코드가 수정될 때마다 Reload를 해준다.

여기서 0.0.0.0의 의미는 모든 포트에 대해 Serve하겠다는 의미다.

 

특별한 의미의 IP 주소

👣 개요 공부를 하는 와중에 0.0.0.0과 127.0.0.1에 대한 공부를 진행하며 혹시 특별한 의미를 지닌 다른 IP는 없을까해서 진행한 공부 내용물. 👣 0.0.0.0 모든 네트워크 인터페이스를 의미하는 IP 주

ikadnorth.tistory.com

 

👣 @app.route - 메서드 편

라우팅(route)을 처리하기 위한 데코레이터다.
데코레이터의 대상인 메소드는 관련 요청을 처리하고 응답을 하는 역할을 수행해야 한다.

GET /test HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Accept: text/html
@app.route('/test')
def index():
    return 'Hello, World!'

위 코드는 첫번째에 제시한 요청에 대해 반응해 요청을 보낸다.
Flask는 다음과 같은 응답을 건네준다.

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

Hello, World!

예시를 보면 알 수 있지만 index() 메소드가 Return을 문자열로 주면 Body에 해당 문자열을 전달한다.
하지만 문자열이 아닌 객체도 Return 할 수 있다.

1. 튜플
튜플은 (response, status, headers) 형식으로 반환된다.
예를 들어 다음과 같다.

@app.route('/custom_response')
def custom_response():
    response = "<html><body><h1>Custom Response</h1></body></html>"
    status_code = 200
    headers = {'Content-Type': 'text/html'}

    return response, status_code, headers

2. Response 객체
flask.Response라는 클래스의 인스턴스를 Return하면 더 세밀하게 응답할 수 있다.

from flask import Flask, Response

@app.route('/custom_response')
def custom_response():
    response_text = "<html><body><h1>Custom Response</h1></body></html>"
    headers = {'Content-Type': 'text/html'}

    response = Response(response=response_text, status=200, headers=headers)
    return response

3. 사용자 정의 클래스
만약 직접 만든 클래스라도 오류 없이 Return 할 수 있다.
해당 인스턴스의 응답은 __str__라는 매직 메서드를 사용해서 해당 문자열을 Body로 기록한다.

class CustomResponse:
    def __init__(self, data):
        self.data = data

    def __str__(self):
        return f"This is a custom response with data: {self.data}"

@app.route('/custom_response')
def custom_response():
    response = CustomResponse(data="example_data")
    return response

4. 딕셔너리 
딕셔너리는 간단하게 Json으로 변환되어 전달된다.

@app.route('/data')
def data():
    data_dict = {'name': 'John', 'age': 30, 'email': 'john@example.com'}
    return data_dict

5. render_template 인스턴스
render_template는 templates 폴더 내부의 Html 파일을 찾아 해당 내용을 응답 Body에 기록하는 메서드다.
render_template는 동적으로 Html을 작성해서 출력하기도 하는데 방법은 다음과 같다.
아래 {{  }} 안에 정의된 변수에 맞춰 파라미터를 전달하면 해당 자리에 값이 기입되어 응답한다.

참고로 해당 메서드가 사용하는 템플릿 엔진의 이름은 Jinja2다.

@app.route('/hello')
def hello():
    name = "Name Example"
    return render_template('hello.html', name=name)
<!-- root/templates/hello.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Hello Page</title>
</head>
<body>
    <h1>Hello, {{ name }}!</h1>
</body>
</html>

 

👣 @app.route - URL 파라미터 추출

URL를 동적으로 감지하고 해당 URL를 파싱해서 처리해야 할 때가 존재한다.
예를 들어, http://localhost/user-page/102345 라는 URL로 요청이 들어올 때,
회원 번호 102345 인 사람의 유저 페이지를 건네줘야 하는 상황이 찾아 온다.
이런 경우를 대비해 다음과 같은 규칙이 존재한다.

@app.route('/user/<int:user_id>')
def get_user(user_id):
    return f"User ID: {user_id}"

위와 같이 <  > 내부에 "{타입 Converter}:{변수명}" 혹은 "{변수명}"을 적으면 알아서 파싱을 해준다.
참고로 타입 Converter는 메서드 이름을 괄호 없이 전달하면 된다.
만약 Converter를 지정하지 않으면 문자열로 Parsing 해준다.

 

👣 @app.route - Parameter 사용

URL에 함께 딸려오는 parameter들을 사용하려면 다음과 같이 request를 사용해야 한다.

GET /user?name=iksadnorth&gender=m HTTP/1.1
Host: localhost:5000
from flask import request

@app.route('/hello')
def hello():
    key = request.args.get('key_name', "default value")
    return "Hello, World!"

 

👣 @app.route - form data 사용

요청을 Form 형식으로 준다면 다음과 같이 데이터를 받을 수 있다.

POST /form HTTP/1.1
Host: localhost:5000
Content-Type: application/x-www-form-urlencoded

name=John&email=john@example.com
@app.route('/form', methods=['POST'])
def process_form():
    name = request.form['name']
    email = request.form['email']
    return f"Name: {name}, Email: {email}"

 

👣 @app.route - Json data 사용

요청을 Json 형식으로 준다면 다음과 같이 데이터를 받을 수 있다.

POST /json HTTP/1.1
Host: localhost:5000
Content-Type: application/json

{
  "name": "John",
  "email": "john@example.com"
}
@app.route('/json', methods=['POST'])
def process_json():
    data = request.get_json()
    name = data['name']
    email = data['email']
    return f"Name: {name}, Email: {email}"

 

'항해 99' 카테고리의 다른 글

Web Scraping  (0) 2023.08.05
Jinja2 템플릿 엔진  (0) 2023.08.05
mongo Atlas  (0) 2023.08.04
Github Pages 배포  (0) 2023.08.03
CSS 선택자  (0) 2023.08.03