Dash App Using Flask Factory Pattern and Blueprint - 1

Page content

강의 홍보

개요

  • 기존 Flask-Dash-Heroku 연동 예제를 업그레이드 한다.
  • Flask Factory Application의 기본 개념 및 Blueprint의 기본 개념을 이해한다.

리뷰

미리보기

  • 다음과 같이 메뉴가 있도록 코드를 작성할 예정이다.

Untitled

Flask Factory Pattern

Flask Blueprint

  • Blueprint의 기본적인 개념은 공식 홈페이지에 잘 나와 있다.
  • 블루프린트를 사용하면 보다 클래스 즉, 같은 종류의 페이지를 묶어서 처리할 수 있도록 도와준다.
    • 예) /book/write/와 /book/read를 쓸 때 /book url로 묶을 수 있다.

배포

Hello World 출력

  • Blueprint와 Factory Method Pattern 방식으로 Hello World를 출력한다.
  • 먼저 가상환경을 만든 후 접속한다.
virtualenv venv # 가상환경 생성
source venv/Scripts/activate # 가상환경 접속
  • 필수 라이브러리를 설치한다.
pip install dash plotly Flask pandas gunicorn psycopg2-binary SQLAlchemy Flask-SQLAlchemy
  • 프로젝트 폴더 (예: dash-flask-factory-blueprint)에서 app 폴더를 생성한다.
    • __init__.py 파일을 만들고 다음과 같이 작성한다.
# app/__init__.py
import os

from flask import Flask

def create_app(test_config=None):
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        SECRET_KEY = 'development'
    )

    if test_config is None:
        app.config.from_pyfile('config.py', silent=True)
    else:
        app.config.from_mapping(test_config)

    try:
        os.makedirs(app.instance_path)
    except OSError:
        pass

    return app
  • 이제 blueprint 코드를 작성하여 Hello World를 출력하도록 한다.
# app/main.py
from flask import Blueprint, render_template

bp = Blueprint('main', __name__, url_prefix='/')

@bp.route('/')
def main():
    return "Hello World!"
  • 이렇게 생성이 되었다면, __init__.py 에서 해당 main.pyblueprint를 등록해야 한다.
# app/__init__.py
import os

from flask import Flask

def create_app(test_config=None):
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        SECRET_KEY = 'development'
    )
    .
    .
    from . import main
    app.register_blueprint(main.bp)

    return app
  • 이번에는 [wsgi.py](http://wsgi.py) 파일을 생성하고 아래와 같이 코드를 추가한다.
from app import create_app

app = create_app()

if __name__ == "__main__":
    app.run(host='0.0.0.0', debug=True)
  • 이제 서버 테스트를 해본다.
    • 정상적으로 나오는지 확인한다.
flask run
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit

Untitled

templates 폴더

  • 이번에는 app폴더 내에 templates 폴더를 만든다.
  • bootstrap 5.2.0 버전을 활용하여 base.html 및 main.html 파일을 생성하여 Manu Bar와 Hello World를 출력하는 코드를 작성한다.
  • 이 때 확장자명 html 파일은 모두 jinja2로 저장하는 것에 주의한다.

(1) header.jinja2 파일 작성

  • 우선 아래와 같이 파일을 작성한다.
    • 파일경로 : app/templates/header.jinja2
<ul class="nav">
  <li class="nav-item">
    <a class="nav-link active" aria-current="page" href="/main">Main</a>
  </li>
  <li class="nav-item">
    <a class="nav-link active" href="/dashapp1">Dashapp1</a>
  </li>
</ul>

(2) base.jinja2 파일 작성

  • 이번에는 기 작성된 header.jinja2를 불러오도록 한다.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Bootstrap demo</title>
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx"
      crossorigin="anonymous"
    />
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa"
      crossorigin="anonymous"
    ></script>
  </head>
  <body>
    {% include 'header.jinja2' %}
    <br />
    <div class="container">{% block content %} {% endblock %}</div>
  </body>
</html>

main 페이지 작성

  • 우선 app/main 폴더를 생성한다.
  • main 폴더 내부에서 templates 폴더와 main.py를 생성한다.

(1) main.jinja2

  • templates 폴더 내부에서 main.jinja2 파일을 아래와 같이 작성한다.
{% extends "base.jinja2" %}

{% block content %}
<h1>Hello World</h1>

{% endblock %}

(2) main.py

  • 이제, main.jinja2 파일을 불러와서 hello world를 출력한다.
# app/main/main.py
from flask import Blueprint, render_template

bp = Blueprint('main', __name__, template_folder = "templates", url_prefix='/')

@bp.route('/')
def main():
    return render_template("main.jinja2", title = 'main page')
  • 이제 app/__init__.py 파일에서 main 코드의 경로를 일부 수정한다.
# app/__init__.py
import os

from flask import Flask

def create_app(test_config=None):
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        SECRET_KEY = 'development'
    )
    .
    .
    from .main import main
    app.register_blueprint(main.bp)

    return app
  • 이제 다시 flask run을 실행하고 달라진 웹페이지를 확인한다.

Untitled

  • 경로를 잠깐 수정하도록 한다.
    • 현재 상태에서 Main, Dashapp1 메뉴를 클릭하면 모두 internal error가 뜬다.
    • 따라서, 기본 html 페이지를 별도로 만들고 127.0.0.1:5000/main 이 나오면 다른 페이지가 나오도록 일부 코드를 변경한다.
  • 우선 app/__init__.py 파일을 아래와 같이 변경한다.
# app/__init__.py
import os

from flask import Flask, render_template

def create_app(test_config=None):
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        SECRET_KEY = 'development'
    )
    .
    .

    @app.route('/')
    def main():
		return render_template("index.jinja2", title = 'index page')

    from .main import main
    app.register_blueprint(main.bp)

    return app
  • app/templates 폴더 내에 index.jinja2 파일을 작성하고 아래와 같이 작성한다.
{% extends "base.jinja2" %}

{% block content %}
<h1>Hello This is 기본 페이지</h1>

{% endblock %}
  • 이번에는 app/main/main.py 를 수정한다.
from flask import Blueprint, render_template

bp = Blueprint('main', __name__, template_folder = "templates", url_prefix='/main')

@bp.route('/', methods=['GET'])
def main():
    return render_template("main.jinja2", title = 'main page')
  • 이제 다시 flask run을 실행하면 아래와 같이 정상적으로 나온다.

Untitled

Untitled

  • 막상 만들고 나니 Home 메뉴가 있으면 좋겠다는 생각이 든다.
    • header.jinja2 의 메뉴바를 수정하면 되는 부분이기 때문에 각자 수정하도록 한다.

Untitled

Dashapp1 페이지 만들기

  • main 폴더를 그대로 복제한 후, 폴더명 및 파일명을 모두 dashapp1으로 변경한다.
    • 방법은 main 폴더에서 했던 방식 그대로다.
  • 이제, app/__init__.py 파일에서 아래와 같이 파일명을 추가한다.
# app/__init__.py
import os

from flask import Flask, render_template

def create_app(test_config=None):
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        SECRET_KEY = 'development'
    )
    .
    .

    @app.route('/')
    def main():
		return render_template("index.jinja2", title = 'index page')

    from .main import main
    from .dashapp1 import dashapp1

    app.register_blueprint(main.bp)
    app.register_blueprint(dashapp1.bp)

    return app
  • 정상적으로 실행이 된 것을 확인할 수 있다.

Untitled