flask 項目基本框架的搭建


綜合案例:學生成績管理項目搭建

 

一 新建項目目錄students,並創建虛擬環境

mkvirtualenv students

 

二 安裝開發中使用的依賴模塊

pip install flask==0.12.4
pip install redis
pip install flask-session
pip install flask-script
pip install flask-mysqldb
pip install flask-sqlalchemy
pip install flask-migrate
pip install flask_wtf

 

三 啟動項目

 

  在pycharm中打開項目目錄編寫manage.py啟動項目的文件

創建 manage.py 文件

from flask import Flask
​
app = Flask(__name__)
​
@app.route('/index')
def index():
    return 'index'if __name__ == '__main__':
    app.run()

 

  mange.py終不能存放大量的開發代碼, 在開發中應該體現的是一種分工精神,所以我們可以把flask中各種功能代碼進行分類分文件存儲.

創建項目目錄結構:

項目根目錄/
├── application/            # 項目主要邏輯代碼保存目錄
|   ├── settings/           # 項目配置存儲目錄
│   │   ├ dev.py            # 開發階段的配置文件
│   │   ├ prop.py           # 生產階段的配置文件
│   ├── __init__.py         # 項目初始化文件
├── manage.py               # 項目的終端管理腳本文件

 

四 配置文件

settings/__init__.py代碼:

from redis import StrictRedis
​
class Config(object):
    """項目配置核心類"""
    # 調試模式
    DEBUG = True
​
    # todo 配置日志
    pass# mysql數據庫的配置信息
 'SQLALCHEMY_DATABASE_URI ="數據庫類型://用戶名:密碼@ip:port:庫名?指定字符集編碼"'
    SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8"
    # 動態追蹤修改設置,如未設置只會提示警告
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查詢時會顯示原始SQL語句
    SQLALCHEMY_ECHO= False
​
    # 配置redis
    REDIS_HOST = '127.0.0.1'  # 項目上線以后,這個地址就會被替換成真實IP地址,mysql也是
    REDIS_PORT = 6379# 設置密鑰,可以通過 base64.b64encode(os.urandom(48)) 來生成一個指定長度的隨機字符串
    SECRET_KEY = "ghhBljAa0uzw2afLqJOXrukORE4BlkTY/1vaMuDh6opQ3uwGYtsDUyxcH62Aw3ju"# flask_session的配置信息
    SESSION_TYPE = "redis" # 指定 session 保存到 redis 中
    SESSION_USE_SIGNER = True # 讓 cookie 中的 session_id 被加密簽名處理
    SESSION_REDIS = StrictRedis(host=REDIS_HOST, port=REDIS_PORT,db=1) # 使用 redis 的實例
    PERMANENT_SESSION_LIFETIME = 24 * 60 * 60 # session 的有效期,單位是秒
settings/dev.py代碼:

from . import Config
class DevelopementConfig(Config):
    """開發模式下的配置"""
    # 查詢時會顯示原始SQL語句
    SQLALCHEMY_ECHO= True
settings/prop.py代碼:

from . import Config
class ProductionConfig(Config):
    """生產模式下的配置"""
    DEBUG = False

 

五 項目主應用中初始化項目

application/__init__.py文件中,創建flask應用並加載配置

from flask import Flask
from application.settings.dev import DevelopementConfig
from application.settings.prop import ProductionConfig
​
config = {
    "dev": DevelopementConfig,
    "prop": ProductionConfig,
}
​
def init_app(config_name):
    """項目的初始化函數"""
    app = Flask(__name__)
​
    # 設置配置類
    Config = config[config_name]
​
    # 加載配置
    app.config.from_object(Config)
​
    return app

 

在manage.py 中調用 init_app 函數,啟動項目

from application import init_app
​
app = init_app("dev")
​
@app.route("/")
def index():
    return "index"if __name__ == '__main__':
    app.run()

 

application/__init__.py項目初始化文件中加載redis或者mysql的初始化代碼

from flask import Flask
from redis import StrictRedis
from flask_wtf.csrf import CSRFProtect
from flask_session import Session
​
from application.settings.dev import DevelopementConfig
from application.settings.prop import ProductionConfig
​
config = {
    "dev": DevelopementConfig,
    "prop": ProductionConfig,
}
​
# 為了方便redis的連接對象在函數外部可以使用,預先設置一個全局變量,接下來在函數中用於保存redis的連接
redis_store = None
​
def init_app(config_name):
    """項目的初始化功能"""
    app = Flask(__name__)
​
    # 設置配置類
    Config = config[config_name]
​
    # 加載配置
    app.config.from_object(Config)
​
    # redis的鏈接初始化
    global redis_store
    redis_store = StrictRedis(host=Config.REDIS_HOST, port=Config.REDIS_PORT,db=0)
​
    # 開啟CSRF防范功能
    CSRFProtect(app)
​
    # 開啟session功能
    Session(app)
​
    # TODO 注冊藍圖對象到app應用中
return app

 

六 增加數據庫配置

# from flask import Flask
# from redis import StrictRedis
# from flask_wtf.csrf import CSRFProtect
# from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
# 
# from application.settings.dev import DevelopementConfig
# from application.settings.prop import ProductionConfig
# 
# config = {
#     "dev": DevelopementConfig,
#     "prop": ProductionConfig,
# }
# 
# # 為了方便redis的連接對象在函數外部可以使用,預先設置一個全局變量,接下來在函數中用於保存redis的連接
# redis_store = None
db = SQLAlchemy()
# 
# def init_app(config_name):
#     """項目的初始化功能"""
#     app = Flask(__name__)
# 
#     # 設置配置類
#     Config = config[config_name]
# 
#     # 加載配置
#     app.config.from_object(Config)
# 
#     # redis的鏈接初始化
#     global redis_store
#     redis_store = StrictRedis(host=Config.REDIS_HOST, port=Config.REDIS_PORT,db=0)
# 
#     # 開啟CSRF防范功能
#     CSRFProtect(app)
# 
#     # 開啟session功能
#     Session(app)
# 
    # 配置數據庫鏈接
    db.init_app(app)
# 
#     # TODO 注冊藍圖對象到app應用中
# 
#     return app
因為前面已經在settings中設置了數據庫的配置信息,所以接下來,創建對應的數據庫

create database students charset=utf8;

 

七 在manage啟動文件中新增關於啟動過程中的相關功能

在項目根目錄下`manage.py中設置項目啟動程序並調用__init__.py的app

from application import init_app,db
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
​
app = init_app("dev")
​
# 使用終端腳本工具啟動和管理flask
manager = Manager(app)
​
# 啟用數據遷移工具
Migrate(app, db)
# 添加數據遷移的命令到終端腳本工具中
manager.add_command('db', MigrateCommand)
​
​
@app.route("/")
def index():
    return "index"if __name__ == '__main__':
    manager.run()

 

八 日志

Python 自身提供了一個用於記錄日志的標准庫模塊:logging。

 

日志的等級

FATAL/CRITICAL = 致命的,危險的
ERROR = 錯誤
WARNING = 警告
INFO = 信息
DEBUG = 調試
NOTSET = 沒有設置

 

application/__init__.py里面把日志設置封裝成一個函數

import logging
from logging.handlers import RotatingFileHandler
​
# 把日志相關的配置封裝成一個日志初始化函數
def setup_log(Config):
    # 設置日志的記錄等級
    logging.basicConfig(level=Config.LOG_LEVEL)  # 調試debug級
    # 創建日志記錄器,指明日志保存的路徑、每個日志文件的最大大小、保存的日志文件個數上限
    file_log_handler = RotatingFileHandler("logs/log", maxBytes=1024 * 1024 * 300, backupCount=10)
    # 創建日志記錄的格式 日志等級 輸入日志信息的文件名 行數 日志信息
    formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
    # 為剛創建的日志記錄器設置日志記錄格式
    file_log_handler.setFormatter(formatter)
    # 為全局的日志工具對象(flaskapp使用的)添加日志記錄器
    logging.getLogger().addHandler(file_log_handler)

 

在application/init_app 方法中調用上一步創建的方法,並傳入 config_name

    # 啟用日志功能
    setup_log(Config)

 

在配置文件settings/__init__.py中,設置默認日志等級

class Config(object):
    """項目配置核心類"""
    # 調試模式
    DEBUG = True
​
    # todo 配置日志
    LOG_LEVEL = "DEBUG"

 

新增日志以后的項目目錄結構

項目根目錄/
├── docs/                   # 項目開發相關文檔
├── logs/                   # 項目運行日志保存目錄
|   ├── log                 # 日志文件
├── application/            # 項目主要邏輯代碼保存目錄
|   ├── settings/           # 項目配置存儲目錄
│   │   ├ dev.py            # 開發階段的配置文件
│   │   ├ prop.py           # 生產階段的配置文件
│   ├── __init__.py         # 項目初始化文件
├── manage.py               # 項目的終端管理腳本文件

 

經過上面的改造,我們接下來就可以開始創建藍圖了。

 

九 創建藍圖目錄

在applications下創建apps目錄,apps以后專門用於保存每一個項目的藍圖,

並在apps創建index藍圖目錄,並在__init__.py文件中創建藍圖對象

from flask import Blueprint
​
index_blu = Blueprint("index_blu",__name__)

 

在index藍圖目錄中新增對應的視圖文件,代碼:

from . import index_blu
​
@index_blu.route("/")
def index():
    return "首頁"

 

__init__.py中引入當前藍圖下所有的視圖文件

from flask import Blueprint
​
index_blu = Blueprint("index_blu",__name__)
​
from .views import *

 

在項目初始化文件application/__init__.py文件中,注冊藍圖對象

    # TODO 注冊藍圖對象到app應用中
    # 首頁模塊
    from .apps.index import index_blu
    app.register_blueprint(index_blu,url_prefix='')

 

聲明了藍圖目錄以后的項目目錄結構

項目根目錄/
├── application/            # 項目主要邏輯代碼保存目錄
|   ├── settings/           # 項目配置存儲目錄
│   │   ├ dev.py            # 開發階段的配置文件
│   │   ├ prop.py           # 生產階段的配置文件
│   ├── __init__.py         # 項目初始化文件
│   ├── statics/            # 保存項目中所有的靜態資源文件[img/css/js]
│   ├── modules/            # 保存項目中所有藍圖的存儲目錄
│   │   ├── index           # 藍圖目錄
│   │   │   ├── __init__.py # 藍圖的初始化問年間
│   │   │   └── views.py    # 藍圖的視圖函數文件
│   │   ├── __init__.py     
├── manage.py               # 項目的終端管理腳本文件

 

index/models.py文件中寫入如下模型代碼:

# coding=utf-8
from application import db
​
# 創建關系表,不再創建模型,一般用於表與表之間的多對多場景
"""
表關系變量 = db.Table(
    "關系表表名",
    db.Column('字段名', 字段類型, 字段選項),  # 普通字段
    db.Column("字段名", 字段類型, db.ForeignKey("表名.id")),
    db.Column("字段名", 字段類型, db.ForeignKey("表名.id")),
)
"""
achievement = db.Table(
    "achievement",
    db.Column('score', db.Numeric, comment="分數"),
    db.Column('student_id', db.Integer, db.ForeignKey('student.id')),
    db.Column('course_id', db.Integer, db.ForeignKey('course.id'))
)
​
class Student(db.Model):
    """學生信息"""
    __tablename__ = "student"
    id = db.Column(db.Integer, primary_key=True, comment="主鍵ID")
    name = db.Column(db.String(64), index=True, comment="姓名" )
    sex = db.Column(db.Boolean, default=True, comment="性別")
    class_number = db.Column(db.String(32), nullable=True, index=True, comment="班級")
    age = db.Column(db.SmallInteger, comment="年齡")
    description = db.Column(db.Text, comment="個性簽名")
    courses = db.relationship(
        'Course', # 模型名稱
        secondary=achievement, # 表關系變量
        backref='students', # 當外鍵反過來獲取主鍵信息時,使用的字段名稱,可以自定義,接下來的使用例如: course.students 獲取某個課程下所有的學生
        lazy='dynamic'
    )
​
class Course(db.Model):
    """課程信息"""
    __tablename__ = "course"
    id = db.Column(db.Integer, primary_key=True,comment="主鍵ID")
    name = db.Column(db.String(64), unique=True,comment="課程名稱")

 

manage.py中導入模型,為了接下來的數據遷移做准備

# 導入模型[為了進行數據遷移]
from application.apps.index.models import Student

 

注意 :必須導入,否則不會生成模型對應的表

 

數據遷移命令

1. 初始化數據遷移的目錄
python manage.py db init
​
2. 數據庫的數據遷移版本初始化
python manage.py db migrate -m 'initial migration'3. 升級版本[創建表]
python manage.py db upgrade 
​
4. 降級版本[刪除表]
python manage.py db downgrade

 

打開終端,在student表中添加測試數據

insert into student values 
(1,"趙華",1,307,22,"對於勤奮的人來說,成功不是偶然;對於懶惰的人來說,失敗卻是必然。"),
(2,"程星雲",1,301,20,"人生應該如蠟燭一樣,從頂燃到底,一直都是光明的。"),
(3,"陳峰",1,504,21,"在不瘋狂,我們就老了,沒有記憶怎么祭奠呢?"),
(4,"蘇禮就",1,502,20,"不要為舊的悲傷,浪費新的眼淚。"),
(5,"張小玉",0,306,18,"沒有血和汗水就沒有成功的淚水。"),
(6,"吳傑",1,307,19,"以大多數人的努力程度之低,根本輪不到去拼天賦"),
(7,"張小辰",0,405,19,"人生的道路有成千上萬條, 每一條路上都有它獨自的風景。")

 

學生頁面展示

在`application/apps/index/templates/students.html寫入前端代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!--注意url_for書寫格式 url_for('藍圖別名.視圖函數名')-->
    <a href="{{ url_for('index_blu.students') }}">新增學員</a>
    <table border="1" align="center" width="1000px">
        <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>年齡</th>
            <th>性別</th>
            <th>班級</th>
            <th>個性簽名</th>
        </tr>
        {% for student in students %}
        <tr>
            <td>{{ student.id }}</td>
            <td>{{ student.name }}</td>
            <td>{{ student.age }}</td>
            <td>{{ student.sex }}</td>
            <td>{{ student.class_number }}</td>
            <td>{{ student.description }}</td>
        </tr>
        {% endfor %}
​
    </table>
</body>
</html>

 

 

application/apps/index/views.py寫入后端代碼

#顯示學生信息
@index_blu.route('/students')
def students():
​
    return render_template('students.html')

 

添加學生

在`application/apps/index/templates/add_students.html寫入前端代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="" method="post">
    {% for message in get_flashed_messages() %}
    <span>{{message}}</span>
    {% endfor %}
    <table width="600px" align="center" border="1">
        <tr>
            <td>姓名:</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td>年齡:</td>
            <td><input type="number" name="age"></td>
        </tr>
        <tr>
            <td>性別:</td>
            <td>
                <select name="sex">
                    <option value="1"></option>
                    <option value="0"></option>
                </select>
            </td>
        </tr>
        <tr>
            <td>班級:</td>
            <td><input type="text" name="class_number"></td>
        </tr>
        <tr>
            <td>個性簽名:</td>
            <td><textarea name="description"></textarea></td>
        </tr>
        <tr>
            <td>&nbsp;</td>
            <td>
                <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
                <input type="submit" value="註冊">
            </td>
        </tr>
    </table>
    </form>
</body>
</html>
 

在application/apps/index/views.py寫入后端代碼

@index_blu.route("/add",methods=["POST","GET"])
def add_student():
    if request.method == "POST":
        # 接受數據
        name = request.form.get("username")
        age = int( request.form.get("age") )if request.form.get("age") else 0
        sex = True if request.form.get("sex") == '1' else False
        class_number = request.form.get("class_number")
        description = request.form.get("description")
        # 驗證數據
        if age < 0 or age > 120:
            # 閃現信息[用於返回錯誤信息給客戶端,只顯示一次]
            flash("非法的年齡數值")
​
        # 保存入庫
        student = Student(name=name,age=age,sex=sex,class_number=class_number,description=description)
        try:
            db.session.add(student)
            db.session.commit()
        except:
            # 事務回滾
            db.session.rollback()
​
    return render_template("add_students.html")

 

十 閃現信息[flash]

  使用后,只會出現一次的信息,叫“閃現信息”,用於在驗證代碼失敗,或者一些只需要顯示一次性提示的場景。

使用步驟:

視圖中驗證有誤,則在顯示模板之前設置flash

# 視圖函數代碼
from flask import flash
​
flash("對不起,您尚未登錄,請登錄!")

 

模板代碼:

# 模板代碼
{% for message in get_flashed_messages() %}
    <span>{{message}}</span>
{% endfor %}

 

最終項目目錄結構如下

 

 

獲取本文flask項目目錄結構代碼:點我

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM