Cấu trúc project Flask để develop web app dễ dàng hơn

Bài viết trước đã giới thiệu qua về cách làm tạo 1 ứng dụng Hello World với Flask App tại đây, hôm nay mình sẽ thử cấu trúc lại Flask App để develop Web App dễ dàng và khoa học, trông khác cái bãi rác hơn.

Bắt tay vào làm luôn thôi.(Thực hiện trên Mac OS, Ubuntu cũng gần tương tự)

Chuẩn bị môi trường

Cài virtualenv đơn giản bằng pip, đây là tool để tạo môi trường Python ảo chạy độc lập và không ảnh hưởng đến hệ thống)

pip3 install virtualenv  

Chuẩn bị cấu trúc application

  • Cấu trúc folder trước đã nào, tạm thời gọi project là flask-starter
cd ~/  
mkdir flask-starter  
  • Như bài trước, chúng ta cũng cần 2 thư mục là statictemplates, nhưng lần này đặt trong thư mục app
cd flask-starter  
mkdir app  
mkdir app/static  
mkdir app/templates  
  • Cấu trúc thư mục giờ trông sẽ như thế này
~/flask-starter
  |__/app
     |__/statics
     |__/templates
  • Tạo virtualenv nào
cd ~/flask-starter  
virtualenv venv  
  • Cài đặt Flask
pip3 install flask  
  • Tạo file .env để lưu các biến môi trường
touch .env  
  • Thêm config vào file
source venv/bin/activate

export FLASK_APP="run.py"  
export SECRET=''  
export APP_SETTINGS="development"  
  • Save file .env, để project sử dụng virtual environment:
source .env  
  • Cấu trúc thư mục giờ sẽ trông thành như thế này
~/flask-starter
  |__/app
     |__/statics
     |__/templates
  |--.env
  |__/venv
  • Tạo Application Files: Ở đây ta sẽ tạo ra file main entrypoint và file lưu giữ config cho application
touch ~/flask-starter/run.py  
touch ~/flask-starter/config.py  
touch ~/flask-starter/app/__init__.py  
  • Và giờ cấu trúc thư mục thành như thế này:
~/flask-starter
  |__/app
     |__/statics
     |__/templates
     |--__init__.py
  |--.env
  |__/venv
  |--config.py
  |--run.py

Module hoá với tính năng Blueprint của Flask

Flask sử dụng 1 concept gọi là Blueprint để tạo những components của App, nhờ đó đối với các ứng dụng lớn, Blueprint giúp mở rộng các tính năng dễ dàng hơn. Chi tiết hơn tại http://flask.pocoo.org/docs/0.12/blueprints/

Ở đây mình sẽ tạo ra module pages, mục đích sẽ không ngoài việc in Hello World quen thuộc.

mkdir ~/flask-starter/app/mod_pages  
touch ~/flask-starter/app/mod_pages/__init__.py  
touch ~/flask-starter/app/mod_pages/controllers.py  
  • Cấu trúc thư mục hiện tại sẽ trông như thế này:
~/flask-starter
  |__/app
     |--__init__.py
     |__/statics
     |__/templates
     |__/mod_pages
        |--__init__.py
        |--controllers.py
  |--.env
  |__/venv
  |--config.py
  |--run.py
  • Trong controllers.py sẽ định nghĩa các action, tương ứng đó sẽ là các view trong templates, ở đây là chỉ có VD Hello World với action hello nên sẽ tạo hello.htmltemplates. Ngoài ra ta tạo thêm file 404.html để handler khi Not Found
~/flask-starter
  |__/app
     |--__init__.py
     |__/statics
     |__/templates
        |--404.html
        |__/pages
           |--hello.html
     |__/mod_pages
        |--__init__.py
        |--controllers.py
  |--.env
  |__/venv
  |--config.py
  |--run.py

Lắp ghép các thành phần lại với nhau:

  • Chỉnh sửa run.py:
from app import app

if __name__ == '__main__':  
    app.run()
  • Chỉnh sửa config.py:
# Statement for enabling the development environment
DEBUG = True

# Define the application directory
import os  
BASE_DIR = os.path.abspath(os.path.dirname(__file__))

# Application threads. A common general assumption is
# using 2 per available processor cores - to handle
# incoming requests using one and performing background
# operations using the other.
THREADS_PER_PAGE = 2

# Enable protection agains *Cross-site Request Forgery (CSRF)*
CSRF_ENABLED     = True

# Use a secure, unique and absolutely secret key for
# signing the data. 
CSRF_SESSION_KEY = "secret"

# Secret key for signing cookies
SECRET_KEY = "secret"

# Auto reload templates
TEMPLATES_AUTO_RELOAD = True  
  • Tạo __init__ file :
touch ~/flask-starter/app/__init__.py  

Paste vào file app/__init__.py

from flask import Flask, render_template, url_for, redirect  
import os

app = Flask(__name__)

app.config.from_object('config')

from app.mod_pages.controllers import mod_pages as pages_module

app.register_blueprint(pages_module)

@app.errorhandler(404)
def not_found(error):  
    return render_template('404.html')
  • Tạp layout cho ứng dụng:
touch ~/flask-starter/app/templates/layout.html  

Layout chứa bộ khung HTML, đảm bảo việc DRY code, giúp maintain dễ dàng hơn:

<!DOCTYPE html>  
<html lang="en">  
<head>  
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <title>Flask Starter App - Kienphan</title>
  <link href="{{ url_for('static', filename = 'css/style.css') }}" rel="stylesheet">
</head>

<body>  
  {% block body %}{% endblock %}
</body>  
</html>  
  • Edit file hello.html để có thể sử dụng layout:
{% extends "layout.html" %}
{% block body %}
  <h1>Hello Flask</h1>
{% endblock %}
  • Edit lại 404.html:
<!DOCTYPE html>  
<html>  
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Page Not Found</title>
  </head>
  <body>
    <div id="message">
      <h2>404</h2>
      <h1>Page Not Found</h1>
      <p>The specified file was not found on this website. Please check the URL for mistakes and try again.</p>
    </div>
  </body>
</html>  

Run và tận hưởng thành quả

phankien@neik flask-starter *$ python3 run.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 118-513-369

Truy cập localhost:5000 ta sẽ gặp ngay trang 404 Not Found do route '/' chưa được định nghĩa. Thử route hello ta đã định nghĩa trong mod_pages xem sao : localhost:5000/pages/hello, ta sẽ thấy render ra trang Hello Flask với màu xanh lá cây quen thuộc.

Mình cũng đã push code lên Repo cá nhân để tham khảo tại đây.

Related article