1. 程式人生 > >Flask框架(三)

Flask框架(三)

一 flask_wtf與flask_bootstrap

  1. flask_wtf表單處理
    上一篇部落格中提出flask_wtf是用來處理表單資料的,而其中
    表單型別(StringField、 PasswordField、 SubmitField、 FileField 等)
    用來驗證的表單有(DataRequired、Length、 Email、 Regexp、 EqualTo),這些在上一篇部落格中有詳細的解釋說明,但是隻有一個簡單的應用,這裡會具體的講解應用
    在建立一個新的專案的時候,通常會有一些行業內通俗的模組與包的名字,比如:static(放置靜態檔案處:css樣式,js樣式等)、templatems(放置html檔案處)等
    而整個專案中除了主函式(
    run.py
    )外,還會有一些其他檔案,forms.py 就是放置 flask_wtf 表單處理的檔案,關於表單處理的要求,會被寫在這個檔案下,當然還會有其它的檔案,下面講到了,會提及的。

首先,要做的就是安裝 flask_wtf 這個庫

pip install flask-WTF

注意:這裡在安裝的時候,看好庫名,是 -WTF ,並不是 _wtf ,但是在應用的時候,卻是後者

from flask_wtf import FlaskForm

匯入這個庫裡面的 FlaskForm這個類
這裡圖簡單一點,會一次性匯入許多的東西,當然都是下面的例子會用到的

from wtforms import StringField, PasswordField, SubmitField, FileField

匯入一些常用的表單型別,相當於input標籤中type的作用

from wtforms.validators import DataRequired, Length, Email, Regexp, EqualTo

匯入一些常用的驗證表單,用來確保表單內容是否合法
這裡寫一個使用者登陸和註冊時的案例,flask_wtf的作用就是用來限制登陸和註冊時的資訊

from flask_wtf import FlaskForm
# 確定表單的型別, 相當於input標籤中type的作用
from wtforms import StringField, PasswordField, SubmitField, FileField
# 確保表單內容是否合法;
from wtforms.validators import DataRequired, Length, Email, Regexp, EqualTo



# Regexp == regular experssion (用於編寫正則表示式的)
class LoginForm(FlaskForm):
    user = StringField(
        label="使用者名稱/手機/郵箱",
        validators=[
            DataRequired(message="使用者名稱不能為空"),
            Length(5, 12),
        ]
    )
    passwd = PasswordField(
        label="密碼",
        validators=[
            Length(6)
        ]
    )
    submit = SubmitField(
        label="登入"

    )


class RegisterForm(FlaskForm):
    user = StringField(
        label="使用者名稱/手機/郵箱",
        validators=[
            Length(5, 12),
        ]
    )
    email = StringField(
        label="郵箱",
        validators=[
            Email("郵箱格式不正確!")
        ]
    )
    phone = StringField(
        label="電話",
        validators=[
            Regexp(r'1\d{10}', message="手機格式不正確!")
        ]
    )
    passwd = PasswordField(
        label="密碼",
        validators=[
            Length(6)
        ]
    )

    repasswd =  PasswordField(
        label="確認密碼",
        validators=[
          EqualTo('passwd', "兩次密碼不一致!")
        ]

    )

    submit = SubmitField(
        label="註冊"

    )

上面的程式碼,需要注意的一點就是:

lable:(是用來對要填寫內容的提示)
validators:(是用來對要填寫內容的限制),一些具體的限制內容祥解,在上一篇部落格中寫過

這裡還有一點,被我藏起來了(沒想到吧),沒寫到上面的程式碼中,下面來提起
在使用者註冊的時候,有時候會被要求,上傳影象,這裡就有不同的地方了
來,劃重點:

face = FileField(
        label="上傳頭像",
        validators=[
            FileAllowed(['png', 'jpg'], message="檔案非圖片")
        ]
    )

validators 中的 FileAllowed 是從from flask_wtf.file import FileAllowed這裡匯出的,還有 FileRequired(必填檔案) 也一樣,並不同於其它的要求

  1. flask_bootstrap網頁編寫
    flask_bootstrap 是用來編寫html檔案的基模版
    其中bootstrap下面有 base.html 這樣的基模版,當然,你也可以自己編寫模版

下面是需要注意的幾點:
1). 如何在flask中使用Boostrap?
要想在程式中整合Bootstrap,顯然要對模板做所有必要的改動。不過,更簡單的方法是使用一個名為Flask-Bootstrap 的Flask 擴充套件,簡化整合的過程。Flask-Bootstrap 使用pip安裝:

pip install flask_bootstrap

2). Flask 擴充套件一般都在建立程式例項時初始化,下面是Flask_Bootstrap的初始化方法

from flask_bootstrap import  Bootstrap

app = Flask(__name__)
bootstrap = Bootstrap(app)

初始化Flask-Bootstrap 之後,就可以在程式中使用一個包含所有Bootstrap 檔案的基模板。這個模板利用Jinja2 的模板繼承機制,讓程式擴充套件一個具有基本頁面結構的基模板,其中就有用來引入Bootstrap 的元素。

3). 如何引用bootatrap的基模板?

{%extends "bootstrap/base.html"%}

{%block title %}Flask{% endblock %}

這兩個塊分別表示頁面中的導航條和主體內容。在這個模板中,navbar 塊使用Bootstrap 元件定義了一個簡單的導航條。content 塊中有個

容器,其中包含一個頁面頭部。

4). Flask-Bootstrap定義的其他可用塊
參考連結:https://pythonhosted.org/Flask-Bootstrap/basic-usage.html#available-blocks

在這裡插入圖片描述

恩~,還是翻譯一下:

塊名 說明
doc 整個html文件
html_attribs html標籤屬性
html html標籤中的內容
head head標籤中的內容
title title標籤中的內容
metas 一組meta標籤
styles 層疊樣式表定義
body_attribs body標籤的屬性
body body標籤中的內容
navbar 使用者定義的導航條
content 使用者定義的頁面內容
scripts 文件底部的JavaScript 宣告

5). 如何繼承原有內容
上表中的很多塊都是Flask-Bootstrap 自用的,如果直接重定義可能會導致一些問題。例如,Bootstrap 所需的檔案在styles 和scripts 塊中宣告。如果程式需要向已經有內容的塊中新增新內容,必須使用Jinja2 提供的super() 函式。例如,如果要在衍生模板中新增新的JavaScript 檔案,需要這麼定義scripts 塊:

{% block scripts %}
{{ super() }}
<script type="text/javascript" src="my-script.js"></script>
{% endblock %}

二 flask_sqlalchemy

flask_sqlalchemy為 Flask 提供了一個 SQLAlchemy 擴充套件,用來處理資料庫的操作

  1. 快速入門
    常見情況下對於只有一個 Flask 應用,所有您需要做的事情就是建立 Flask 應用,選擇載入配置接著建立 SQLAlchemy 物件時候把 Flask 應用傳遞給它作為引數
    一旦建立,這個物件就包含 sqlalchemy 和 sqlalchemy.orm 中的所有函式和助手。此外它還提供一個名為 Model 的類,用於作為宣告模型時的 delarative 基類
from flask_sqlalchemy import  SQLAlchemy
from flask import  Flask
app = Flask(__name__)

#Flask-SQLAlchemy 中存在的配置值
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:[email protected]/User'

# SQLAlchemy 將會追蹤物件的修改並且傳送訊號。
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

db = SQLAlchemy(app)

具體的配置鍵說明:

配置鍵 說明
SQLALCHEMY_DATABASE_URI 用於連線資料的資料庫,例如:sqlite:////tmp/test.db; mysql://username:[email protected]/db
SQLALCHEMY_TRACK_MODIFICATIONS 如果設定成 True (預設情況),Flask-SQLAlchemy 將會追蹤物件的修改並且傳送訊號。這需要額外的記憶體, 如果不必要的可以禁用它。

當然 mysql://username:[email protected]/db 在連線的時候,預設的是 Python2 中的 MySQLdb 。要想使用 Python3 中的 pymysql ,需要在mysql+pymysql://username:[email protected]/db 後面加上 mysql+pymysql
這樣才是完整連線 URI 格式,才會連線上Python3中使用的資料庫

  1. 簡單示例
    通常下,Flask-SQLAlchemy 的行為就像一個來自 declarative 擴充套件配置正確的 declarative 基類;您的所有模型的基類叫做 db.Model。它儲存在您必須建立的 SQLAlchemy 例項上。

一個簡單的示例:

class User(db.Model):
   #  __tablename__ = "students"	
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)
    
    def __repr__(self):
        return '<User %r>' % self.username

其中:
1). 預設情況下建立一個表, 表名為類名; 如果指定了__tablename__, 那麼表名為你指定的名稱
2). 用 Column 來定義一列。列名就是您賦值給那個變數的名稱。如果您想要在表中使用不同的名稱,您可以提供一個想要的列名的字串作為可選第一個引數
3). 主鍵用 primary_key=True 標記。可以把多個鍵標記為主鍵,此時它們作為複合主鍵
4). 列的型別是 Column 的第一個引數。您可以直接提供它們或進一步規定(比如提供一個長度)。下面的型別是最常用的:

型別 解釋說明
Integer 一個整數
String (size) 有長度限制的字串
Text 一些較長的 unicode 文字
DateTime 表示為 Python datetime 物件的 時間和日期
Float 儲存浮點值
Boolean 儲存布林值
PickleType 儲存為一個持久化的 Python 物件
LargeBinary 儲存一個任意大的二進位制資料
  1. 一對多關係
    最為常見的關係就是一對多的關係。因為關係在它們建立之前就已經宣告,您可以使用 字串來指代還沒有建立的類。

一對多的簡單示例:

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    addresses = db.relationship('Address', backref='person')
                               

class Address(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(50))
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))

其中:
1). 一的一端需要寫反向引用:關係使用 relationship() 函式表示
2). 多的一端需要寫外來鍵:必須用類 sqlalchemy.schema.ForeignKey 來單獨宣告

還有一點需要注意:

db.drop_all()

建立定義的表結構

db.create_all()

刪除定義的表結構

  1. 資料庫的增刪改查
    這是我剛才運用上面提到的點,建立了一個數據庫:
    當然在建立之前,需要先建立一個,中文編碼格式的庫,
CREATE DATABASE User CHARACTER SET utf8 COLLATE utf8_general_ci;

然後再在庫上建立資料。

from datetime import datetime
from flask_sqlalchemy import  SQLAlchemy
from flask import  Flask
from sqlalchemy import desc
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:[email protected]/User'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)

# 使用者表
class User(db.Model):
    # autoincrement=True自增
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    #  unique=True, name的值不能重複, 是唯一的;
    name = db.Column(db.String(50), unique=True)
    # 長度為100, 是因為網站密碼一般會加密;
    passwd = db.Column(db.String(100))
    # 指定使用者註冊/建立的時間,
    # default, 指定預設值, datetime.now()獲取當前時間;
    # 使用者註冊時間為當前時間;
    add_time = db.Column(db.DateTime, default=datetime.now())
    # 使用者的角色id,不能隨便寫, 必須要關聯其他的資料庫表(role) --- 外來鍵
    role_id = db.Column(db.INTEGER, db.ForeignKey('role.id'))

    def __repr__(self):
        return '<User:%s>' %(self.name)

# 使用者角色表
class Role(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    name = db.Column(db.String(50), unique=True)
    #  Role表中的users屬性與User表關聯, 並且User這個表中可以由role這個物件屬性;
    users = db.relationship('User',backref='role')

    def __repr__(self):
        return  "<Role:%s>" %(self.name)

if __name__ == '__main__':
    db.create_all()

執行結果:
在這裡插入圖片描述

1). 增加資料
在查詢資料之前我們必須先插入資料。您的所有模型都應該有一個建構函式,如果您 忘記了,請確保加上一個。只有您自己使用這些建構函式而 SQLAlchemy 在內部不會使用它, 所以如何定義這些建構函式完全取決與您。
向資料庫插入資料分為三個步驟:

1.	建立 Python 物件
2.	把它新增到會話
3.	提交會話

這裡的會話不是 Flask 的會話,而是 Flask-SQLAlchemy 的會話。它本質上是一個 資料庫事務的加強版本。它是這樣工作的:

建立使用者角色:

role1 = Role(name="超級會員")
role2 = Role(name="會員")

db.session.add(role1)
db.session.add(role2)

db.session.commit()

執行結果:
在這裡插入圖片描述

新增100個使用者,其中50個為超級會員, 50個為會員:

    for i in range(50):
        u = User(name='westos%s' %(i), passwd='westos', role_id=1)
        db.session.add(u)
    db.session.commit()


    for i in range(50):
        u = User(name='redhat%s' % (i), passwd='redhat', role_id=2)
        db.session.add(u)
    db.session.commit()

執行結果:
在這裡插入圖片描述

2). 查詢資料
Flask-SQLAlchemy 在您的 Model 類上提供了 query 屬性。當您訪問它時,您會得到一個新的所有記錄的查詢物件。在使用 all() 或者 first() 發起查詢之前可以使用方法 filter() 來過濾記錄。

(1)查詢所有資料

print(Role.query.all())
print(User.query.all())

在這裡插入圖片描述

(2)根據條件查詢資料(篩選資料(filter_by)); 相當於slect * from table where xxx=xxx;

    print(User.query.filter_by(role_id=1).all())
    print(User.query.filter_by(role_id=2).all())

在這裡插入圖片描述

(3)對於找到的內容進行更新

    u = User.query.filter_by(name='westos0').first()
    print(u)
    u.passwd = '123456'
    db.session.add(u)
    db.session.commit()

在這裡插入圖片描述

(4)篩選資料方法2(filter),通過這種方式可以檢視原生的sql語句

    user = User.query.filter(User.role_id==1)
    print(user)

在這裡插入圖片描述

(5)對於查詢的資訊進行顯示限制

    users = User.query.filter_by(role_id=1).limit(5).all()
    print(users, len(users), end='\n')

在這裡插入圖片描述

(6)對於查詢的資訊進行排序輸出(預設情況由小到大進行排序), 如果想要由大到小: desc(User.add_time)

    users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).all()
    print(users)

在這裡插入圖片描述

(7)多個過濾函式加一個顯示函式

    users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).limit(5).all()
    print(users)
    #  offset指定偏移量, limit 指定輸出數量, 類似於切片操作;
    #  1 2 3 4 5 6 7 8 9
    #  limit(5): 1 2 3 4 5
    #  limit(5).offset(2): 3 4 5 6 7
    users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).limit(5).offset(2).all()
    print(users)
    # 切片操作li[2:7]
    users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).slice(2,7).all()
    print(users)

    count = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).slice(2, 7).count()
    print(count)

在這裡插入圖片描述

(8)分頁:第一個引數代表顯示第幾頁的資料, 第二個引數代表每頁顯示多少條資料

    users = User.query.paginate(1, 5)
    print(users.items)
    users = User.query.paginate(2, 5)
    print(users.items)

在這裡插入圖片描述

(9)反向引用的使用

    u = User.query.filter_by(name='westos0').first()
    print(u.name, u.passwd, u.add_time, u.role_id, u.role, u.role.id, u.role.name)

在這裡插入圖片描述

3). 刪除資料
刪除資料與增加資料是十分類似的,使用 delete() 代替 add()

    user=User.query.filter_by(name='redhat0').first()
    db.session.delete(user)
    db.session.commit()

在這裡插入圖片描述

這裡有可以參考的兩點:
1-查詢過濾器總結
在這裡插入圖片描述

2-執行函式總結
在這裡插入圖片描述

三 flask_migrate與flask_script

  1. flask_migrate
    Flask-Migrate是用於處理SQLAlchemy 資料庫遷移的擴充套件工具。當Model出現變更的時候,通過migrate去管理資料庫變更
    一般分為三步(init、migrate、upgrade)

  2. flask_script
    Flask_script擴充套件提供向Flask插入外部指令碼的功能,包括執行一個開發用的伺服器,一個定製的Python shell,設定資料庫的指令碼,cronjobs,及其他執行在web應用之外的命令列任務;使得指令碼和系統分開;Flask_script和Flask本身的工作方式類似,只需定義和新增從命令列中被Manager例項呼叫的命令

  3. 結合的簡單使用
    需求:現在,在 Role 資料表中需要新增一個新的屬性(grace:級別),需要該怎麼做,總不能將資料庫刪了重新建吧。
    這裡就需要用到這兩個庫了,做資料庫的擴充套件

可以將程式碼寫在 manage 檔案下,與 models 檔案同級
manage檔案就是存放 關於資料庫擴充套件的檔案

from flask_migrate import  Migrate, MigrateCommand
from flask_script import  Shell, Manager
from models import app, db, User, Role

# 用來管理命令的物件, Manager用來跟蹤所有名林不過並處理他們如何從命令列呼叫;
manager = Manager(app)
migrate = Migrate(app, db)

# 新增一條資料庫管理的命令
manager.add_command('db', MigrateCommand)

#  實現新增使用者的命令
if __name__ == "__main__":
    # 準備
    manager.run()

首先,需要在models檔案中填寫需要新增的屬性
在這裡插入圖片描述

不用執行,manager檔案讀取該檔案就行了

執行manager檔案,可得到:這些位置引數
在這裡插入圖片描述

執行 db 引數後,可得到下列的命令,用來對 models 中建立的資料庫操作

(2048) [[email protected] day30]$ python manage.py db
usage: Perform database migrations

Perform database migrations

positional arguments:
  {init,revision,migrate,edit,merge,upgrade,downgrade,show,history,heads,branches,current,stamp}
    init                Creates a new migration repository
    revision            Create a new revision file.
    migrate             Alias for 'revision --autogenerate'
    edit                Edit current revision.
    merge               Merge two revisions together. Creates a new migration
                        file
    upgrade             Upgrade to a later version
    downgrade           Revert to a previous version
    show                Show the revision denoted by the given symbol.
    history             List changeset scripts in chronological order.
    heads               Show current available heads in the script directory
    branches            Show current branch points
    current             Display the current revision for each database.
    stamp               'stamp' the revision table with the given revision;
                        don't run any migrations

optional arguments:
  -?, --help            show this help message and exit

1).下來就是操作的三部曲了

(1) init : 初始化資料,建立遷移倉庫

python manage.py db init

在這裡插入圖片描述

可以看到,建立了一個 migrations 目錄,其中 versions 就記錄著資料庫的變遷
models 檔案中,不是給 Role 資料表添加了一個 grace 屬性
(2)migrate :增加屬性

python manage.py db migrate -m "Role中新增屬性grace"

其中: -m 可以指定此次操作的名稱
在這裡插入圖片描述
可以看到 versions 檔案中記錄了此次的變化
(3)upgrade :資料庫更新此次變化

python manage.py db upgrade

在這裡插入圖片描述
可以看到,資料庫的更改

2). 當然,此庫還有一個強大的功能就在於,可以返回原先的操作
在這裡插入圖片描述
從歷史中可以檢視到,對原先的資料庫(base),做了更改

退回base狀態:
在這裡插入圖片描述
從資料庫中檢視結果:
在這裡插入圖片描述
可以明顯的看到更改前後的不同之處

3). 當然你也可以自定義一些操作
使用裝飾器來裝飾你的函式
(1)manager.command

@manager.command
def showUser():
    """顯示所有的使用者"""
    users = User.query.all()
    print(users[:5])
# 由於使用者太多了,這裡只顯示前5個

在這裡插入圖片描述
可以看到這裡多個一個位置引數,用來顯示所有的使用者
在這裡插入圖片描述
呼叫這個引數,就可以顯示所有的使用者了

(2)manager.option
同 command 不同的點在於,此方法可以傳遞引數
比如說新增一個角色:

@manager.option('-n', '--name', help="角色名稱")
def add_role(name):
    try:
        role1 = Role(name=name)
        db.session.add(role1)
        db.session.commit()
    except Exception:
        print("建立使用者角色失敗!")
    else:
        print("建立使用者角色%s成功!" %(name))

第一行括號裡面可以寫成幫助文件,用來執行命令
就像 ls 命令一樣在這裡插入圖片描述

第一個為縮寫,第二個為全稱,第三個為幫助文件
在這裡插入圖片描述
在這裡插入圖片描述
建立白金會員成功,當然假如建立已經存在的,當然會失敗了

關於Flask框架的一些基本內容就說到這了。