Flask

flask使用操作指南1


1. flask介紹

Flask是一個基於Python實現的web開發的'微'框架

中文文檔地址

Flask和Django一樣,也是一個基於MVC設計模式的Web框架

flask流行的主要原因:

a)有非常齊全的官方文檔,上手非常方便

b) 有非常好的拓展機制和第三方的拓展環境,工作中常見的軟件都有對應的拓展,自己動手實現拓展也很容易

c) 微型框架的形式給了開發者更大的選擇空間

2. 安裝flask

2.1虛擬環境搭建

virtualenv --no-site-packages falskenv
  
激活windows下虛擬環境
cd Scripts
activate

2.2 安裝

pip install flask

3. 基於flask的最小的應用

創建hello.py文件

from flask import Flask

app = Flask(__name__)

@app.route('/')
def gello_world():
    return 'Hello World'

if __name__ == '__main__':

    app.run()

運行:python hello.py

3.1 初始化

from flask import Flask

app = Flask(__name__)

Flask類構造函數唯一需要的參數就是應用程序的主模塊或包。對於大多數應用程序,Python的__name__變量就是那個正確的、你需要傳遞的值。Flask使用這個參數來確定應用程序的根目錄,這樣以後可以相對這個路徑來找到資源文件。

3.2 路由

@app.route('/')

客戶端例如web瀏覽器發送 請求 給web服務,進而將它們發送給Flask應用程序實例。應用程序實例需要知道對於各個URL請求需要運行哪些代碼,所以它給Python函數建立了一個URLs映射。這些在URL和函數之間建立聯繫的操作被稱之爲 路由 。

在Flask應程序中定義路由的最便捷的方式是通過顯示定義在應用程序實例之上的app.route裝飾器,註冊被裝飾的函數來作爲一個路由

3.3 視圖函數

在上一個示例給應用程序的根URL註冊gello_world()函數作爲事件的處理程序。如果這個應用程序被部署在服務器上並綁定了 www.example.com 域名,然後在你的瀏覽器地址欄中輸入 http://www.example.com 將觸發gello_world()來運行服務。客戶端接收到的這個函數的返回值被稱爲 響應 。如果客戶端是web瀏覽器,響應則是顯示給用戶的文檔。

類似於gello_world()的函數被稱作 視圖函數

3.4 動態名稱組件路由

你的Facebook個人信息頁的URL是 http://www.facebook.com/<username> ,所以你的用戶名是它的一部分。Flask在路由裝飾器中使用特殊的語法支持這些類型的URLs。下面的示例定義了一個擁有動態名稱組件的路由:

@app.route('/hello/<name>')

def gello_world(name):

    return 'Hello World %s' % name

用尖括號括起來的部分是動態的部分,所以任何URLs匹配到靜態部分都將映射到這個路由。當視圖函數被調用,Flask發送動態組件作爲一個參數。在前面的示例的視圖函數中,這個參數是用於生成一個個性的問候作爲響應。

在路由中動態組件默認爲字符串,但是可以定義爲其他類型。例如,路由/user/<int:id>只匹配有一個整數在id動態段的URLs。Flask路由支持int、float、string、path

路由匹配的規則
1.<id> :默認接受的類型是str
2.<string:id> :指定id的類型爲str
3.<int:id> :指定的id類型是整性
4.<float:id> : 指定id的類型爲浮點數(四捨五入,且不能接收整數類型)
5.<path:path1> : 指定接收的path爲url中的路徑

如下:

  
@blue.route('/get_id/<id>/')
def get_id(id):
    #匹配str類型的id值
    return 'id: %s' % id


@blue.route('/get_int_id/<int:id>/')
def get_int_id(id):
    #匹配int類型的id值
    return 'id:%d' % id


@blue.route('/get_float/<float:uid>/')
def get_float(uid):
    #匹配float類型的值,不能匹配int類型(四捨五入)
    return 'uid:%.2f' %uid


@blue.route('/get_path/<path:upath>/')
def get_path(upath):
    #匹配url路徑
    return 'path:%s' % upath

 

3.5 服務啓動

if __name__ == '__main__':

    app.run()

注意: __name__ == '__main__'在此處使用是用於確保web服務已經啓動當腳本被立即執行。當腳本被另一個腳本導入,它被看做父腳本將啓動不同的服務,所以app.run()調用會被跳過。

一旦服務啓動,它將進入循環等待請求併爲之服務。這個循環持續到應用程序停止,例如通過按下Ctrl-C。

有幾個選項參數可以給app.run()配置web服務的操作模式。在開發期間,可以很方便的開啓debug模式,將激活 debugger 和 reloader 。這樣做是通過傳遞debug爲True來實現的。

app.run(host='0.0.0.0',port=8080,debug=True)

run()中參數有如下:

debug 是否開啓調試模式,開啓後修改python的代碼會自動重啓

port 啓動指定服務器的端口號

host主機,默認是127.0.0.1

4. 修改啓動方式,使用命令行參數啓動服務

4.1 安裝插件

pip install flask-script

調整代碼
manager = Manager(app=‘自定義的flask對象’)

啓動的地方
manager.run()

4.2 啓動命令

python hellow.py runserver -h 地址 -p 端口 -d -r

其中:-h表示地址。-p表示端口。-d表示debug模式。-r表示自動重啓

如:
manager.run(python xx.py runserver -h 0.0.0.0 -p 8080 -d)

5. route規則

5.1 規則

寫法:<converter:variable_name>

converter類型:

string 字符串
int 整形
float 浮點型
path 接受路徑,接收的時候是str,/也當做字符串的一個字符
uuid 只接受uuid字符串
any 可以同時指定多種路徑,進行限定

例子:

@app.route('/helloint/<int:id>/')

@app.route('/getfloat/<float:price>/')

@app.route('/getstr/<string:name>/',methods=['GET', 'POST'])

@app.route('/getpath/<path:url_path>/')

@app.route('/getbyuuid/<uuid:uu>/',methods=['GET', 'POST'])

實現對應的視圖函數:

@blue.route('/hello/<name>/')
def hello_man(name):
    print(type(name))
    return 'hello name:%s type:%s' % (name, type(name))


@blue.route('/helloint/<int:id>/')
def hello_int(id):
    print(id)
    print(type(id))
    return 'hello int: %s' % (id)


@blue.route('/index/')
def index():
    return render_template('hello.html')


@blue.route('/getfloat/<float:price>/')
def hello_float(price):
    return 'float: %s' % price


@blue.route('/getstr/<string:name>/')
def hello_name(name):
    return 'hello name: %s' % name


@blue.route('/getpath/<path:url_path>/')
def hello_path(url_path):
    return 'path: %s' % url_path


@blue.route('/getuuid/')
def gello_get_uuid():
    a = uuid.uuid4()
    return str(a)


@blue.route('/getbyuuid/<uuid:uu>/')
def hello_uuid(uu):
    return 'uu:%s' % uu

5.2 methods請求方法

常用的請求類型有如下幾種

GET : 獲取
POST : 創建
PUT : 修改(全部屬性都修改)
DELETE : 刪除
PATCH : 修改(修改部分屬性)

定義url的請求類型:

@blue.route('/getrequest/', methods=['GET', 'POST'])

flask使用操作指南2


1. 什麼是藍圖

在Flask項目中可以用Blueprint(藍圖)實現模塊化的應用,使用藍圖可以讓應用層次更清晰,開發者更容易去維護和開發項目。藍圖將作用於相同的URL前綴的請求地址,將具有相同前綴的請求都放在一個模塊中,這樣查找問題,一看路由就很快的可以找到對應的視圖,並解決問題了。

2. 使用藍圖

2.1 安裝

pip install flask_blueprint

2.2 實例化藍圖應用

blue = Blueprint(‘first’,_ _name_ _)

注意:Blueprint中傳入了兩個參數,第一個是藍圖的名稱,第二個是藍圖所在的包或模塊,_ name _代表當前模塊名或者包名

2.3 註冊

app = Flask(_ _name_ _)

app.register_blueprint(blue, url_prefix='/user')

注意:第一個參數即我們定義初始化定義的藍圖對象,第二個參數url_prefix表示該藍圖下,所有的url請求必須以/user開始。這樣對一個模塊的url可以很好的進行統一管理

3 使用藍圖

修改視圖上的裝飾器,修改爲@blue.router(‘/’)

@blue.route('/', methods=['GET', 'POST'])
def hello():
    # 視圖函數
    return 'Hello World'

注意:該方法對應的url爲127.0.0.1:5000/user/

4 url_for反向解析

語法:

url_for('藍圖中定義的第一個參數.函數名', 參數名=value)

定義跳轉:

from flask import url_for, redirect

@blue.route('/redirect/')
def make_redirect():
    # 第一種方法
    return redirect('/hello/index/')
    # 第二種方法
    return redirect(url_for('first.index'))

flask使用操作指南3


1. 請求request

服務端在接收到客戶端的請求後,會自動創建Request對象

由Flask框架創建,Requesy對象不可修改

屬性:

url:完整的請求地址

base_url:去掉GET參數的url

host_url:只有主機和端口號的url

path:路由中的路徑

method:請求方法

remote_addr:請求的客戶端的地址

args:GET請求參數

form:POST請求參數

files:文件上傳

headers:請求頭

cookies:請求中的cookie

1.1 args-->GET請求參數包裝

a)args是get請求參數的包裝,args是一個ImmutableMultiDict對象,類字典結構對象

b)數據存儲也是key-value

1.2 form-->POST請求參數包裝

a)form是post請求參數的包裝,args是一個ImmutableMultiDict對象,類字典結構對象

b)數據存儲也是key-value

重點:ImmutableMultiDict是類似字典的數據結構,但是與字典的區別是,<font style="color:red; font-weight:bold;">可以存在相同的鍵</font>。

在ImmutableMultiDict中獲取數據的方式,dict['key']或者dict.get('key')或者dict.getlist('key')

image.png

2. 響應Response

Response是由開發者自己創建的

創建方法:

from flask import make_response

make_response創建一個響應,是一個真正的Response對象

狀態碼:

格式:make_reponse(data,code),其中data是返回的數據內容,code是狀態碼

a)直接將內容當做make_response的第一個參數,第二個參數直接寫返回的狀態碼

b)直接在render後加返回的狀態碼

例子1:

定義一個獲取GET請求的request的方法,並將返回成功的請求的狀態碼修改爲200

@blue.route('/getrequest/', methods=['GET'])
def get_request():

    print(request)

    return '獲取request', 200

例子2:

返回response響應,並添加返回結果的狀態碼200

@blue.route('/getresponse/')
def get_response():
    response = make_response('<h2>我是響應</h2>', 500)
    return response

或者:

@blue.route('/getresponse/', methods=['GET'])
def get_user_response():
    login_html = render_template('login.html')
    res = make_response(login_html, 200)
    return res

3. 重定向/反向解析

url_for('藍圖定義的名稱.方法名')

例子1:

定義跳轉方法,跳轉到get_response的方法上

@blue.route('/getredirect/')
def get_redirect():

    return redirect('getresponse')

例子2:

使用url_for反向解析

from flask import redirect, url_for

@blue.route('/getredirect/')
def get_redirect():

    return redirect(url_for('first.get_response'))

4. 終止/異常捕獲

自動拋出異常:abort(狀態碼)

捕獲異常處理:errorhandler(狀態碼),定義的函數中要包含一個參數,用於接收異常信息

4.1 定義終止程序

@blue.route('/make_abort/')
def get_abort():
    abort(400)
    return '終止'

4.2 捕獲定義的異常

@blue.errorhandler(400)
def handler(exception):

    return '捕獲到異常信息:%s' % exception

flask使用操作指南之session/cookie


前言

訪問者的標識問題服務器需要識別來自同一訪問者的請求。這主要是通過瀏覽器的cookie實現的。 訪問者在第一次訪問服務器時,服務器在其cookie中設置一個唯一的ID號——會話ID(session)。 這樣,訪問者後續對服務器的訪問頭中將自動包含該信息,服務器通過這個ID號,即可區 隔不同的訪問者。

1. Cookie

概念:

a)客戶端會話技術,瀏覽器的會話技術

b)數據全部存儲在客戶端中

c)存儲使用的鍵值對結構進行存儲

特性:
    支持過期時間
    默認會自動攜帶本網站的cookie
    不能跨域名
    不能跨瀏覽器

創建:

Cookie是通過服務器創建的Response來創建的

設置:set_cookie('key', value, max_ages='', expires='')

刪除, 有三種刪除方式
    
    1. 直接清空瀏覽器的cookie
    2. delete_cookie('key') 直接使用delete_cookie函數
    3. set_cookie('key','',expires=0) 重新設置key的值爲空,過期時間爲0

獲取:

在每次請求中,url都會向服務器傳遞Request,在request中可以獲取到cookie的信息

request.cookies.get('name')

例子1,設置cookie:

import datetime

@blue.route('/setcookie/')
def set_cookie():
    temp = render_template('index.html')
    response = make_response(temp)
    outdate=datetime.datetime.today() + datetime.timedelta(days=30)
    # 設置cookie中的name的存在時長,設置爲30天才過期  
    response.set_cookie('name','cocoococo',expires=outdate)
    return response

例子2,刪除cookie中的值

@blue.route('/setcookie/')
def set_cookie():
    temp = render_template('index.html')
    response = make_response(temp)
    # 第一種方式,通過set_cookie去刪除
    response.set_cookie('name','',expires=0)
    # 第二種方式,del_cookie刪除
    response.del_cookie('name')
    return response

例子3,獲取cookie中的值

@blue.route('/getcookie/')  
def get_cookie():
    name=request.cookies.get('name')  
    return name

2. Session

flask-session是flask框架的session組件

該組件則將支持session保存到多個地方

如:

redis:保存數據的一種工具,五大類型。非關係型數據庫

memcached

mongodb

sqlalchmey:那數據存到數據庫表裏面

2.1 安裝

pip install flask-session

如果指定存session的類型爲redis的話,需要安裝redis

pip install redis

2.2 語法

設置session:

session['key'] = value

讀取session:

result = session['key'] :如果內容不存在,將會報異常

result = session.get('key') :如果內容不存在,將返回None

刪除session:

session.pop('key')

清空session中所有數據:

session.clear()

2.2 使用

我們在初始化文件中創建一個方法,通過調用該方法來獲取到Flask的app對象

def create_app():
    app = Flask(__name__)
    # SECRET_KEY 祕鑰
    app.config['SECRET_KEY'] = 'secret_key'
    # session類型爲redis
    app.config['SESSION_TYPE'] = 'redis'
    # 添加前綴
    app.config['SESSION_KEY_PREFIX'] = 'flask'
    
    # 加載app的第一種方式
    se = Session()
    se.init_app(app=app)
    #加載app的第二種方式
    Session(app=app)
    app.register_blueprint(blueprint=blue)

    return app

2.3 案例

定義一個登陸的方法,post請求獲取到username,直接寫入到redis中,並且在頁面中展示出redis中的username

a)需要先啓動redis,開啓redis-server,使用redis-cli進入客戶端

b)定義方法

@blue.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        username = session.get('username')
        return render_template('login.html', username=username)
    else:
        username = request.form.get('username')
        session['username'] = username

        return redirect(url_for('first.login'))

c)定義模板

<body>
<h3>歡迎:{{ username }}</h3>
<form action="" method="POST">
    用戶名:<input type="text" name="username" placeholder="請輸入你的名字">
    <input type="submit" value="提交">
</form>
</body>

d)redis中數據


image.png

注意:我們在定義app.config的時候指定了SESSION_KEY_PREFIX爲flask,表示存在session中的key都會加一個前綴名flask

e) cookie和session的聯繫

image.png

訪問者在第一次訪問服務器時,服務器在其cookie中設置一個唯一的ID號——會話ID(session)。 這樣,訪問者後續對服務器的訪問頭中將自動包含該信息,服務器通過這個ID號,即可區 隔不同的訪問者。然後根據不同的訪問者來獲取其中保存的value值信息。

flask使用操作指南之session實現登錄驗證


功能描述

使用session實現用戶的模擬登陸功能。在前面已經說過了,在用戶第一次訪問服務端的時候,在服務端的redis中會創建一個session值,在客戶端瀏覽器的cookies中也會創建一個session的值。該cookies中的session值和redis中的session值是一樣的,那麼在往後的訪問操作中,請求request都會傳遞給後端,後端在獲取到request的時候,其實就是獲取到了request.cookies中的session的值了,那麼就可以做登錄的校驗了。校驗功能如下:

素材地址

1. 前端login.html頁面

登錄頁面就兩個輸入框,分別接收用戶名和密碼

  <dd class="user_icon">
   <input type="text" name="username" placeholder="賬號" class="login_txtbx"/>
  </dd>
  <dd class="pwd_icon">
   <input type="password" name="password" placeholder="密碼" class="login_txtbx"/>
  </dd>

2. 後端方法

模擬用戶的登錄,直接判斷用戶的名稱爲妲己以及密碼爲123123.如果驗證成功,就向session中保存用戶的id值。如果沒有登錄成功的話,那就對session不做任何的處理,直接跳轉到登錄頁面上去。

@app_blue.route('/new_login/', methods=['GET', 'POST'])
def new_login():
    if request.method == 'GET':
        return render_template('login.html')
    else:
        username = request.form.get('username')
        password = request.form.get('password')
        # 數據庫校驗,用戶密碼是否正確
        if username == '妲己' and password == '123123':
            session['user_id'] = 1
            return redirect((url_for('first.index')))
        else:
            return redirect(url_for('first.new_login'))


@app_blue.route('/index/', methods=['GET'])
def index():
return render_template('index.html')

3. 裝飾器

使用裝飾器去裝飾我們的index()函數,如果用戶登錄了,則session中有user_id的key,如果沒有登錄的話,session中是沒有user_id的key的。那麼驗證用戶是否登錄了,其實就是驗證session的user_id

def is_login(func):
    @wraps(func)
    def check_login(*args, **kwargs):
        if 'user_id' in session:
            return func(*args, **kwargs)
        else:
            return redirect(url_for('first.new_login'))
    return check_login

4. 修改index()函數,使用裝飾器裝飾

@app_blue.route('/index/', methods=['GET'])
@is_login
def index():
    return render_template('index.html')

flask使用操作指南之模板


1. jinja2

Flask中使用jinja2模板引擎

jinja2是由Flask作者開發,模仿Django的模板引擎

優點:

速度快,被廣泛使用

HTML設計和後端python分離

非常靈活,快速和安全

提供了控制,繼承等高級功能

2. 模板語法

2.1 模板語法主要分爲兩種:變量和標籤

模板中的變量:{{ var }}

視圖傳遞給模板的數據

前面定義出來的數據

變量不存在,默認忽略

模板中的標籤:{% tag %}

控制邏輯

使用外部表達式

創建變量

宏定義

2.2 結構標籤:

block

{% block xxx %}

{% endblock %}

塊操作
    父模板挖坑,子模板填坑

extends

{% extends ‘xxx.html’ %}

繼承以後保留塊中的內容
{{ super() }}

挖坑繼承體現的化整爲零的操作

macro

{% macro hello(name) %}

    {{ name }}

{% endmacro %}

宏定義,可以在模板中定義函數,在其他地方調用

宏定義可導入

{% from 'xxx' import xxx %}

例子1:

在index.html中定義macro標籤,定義一個方法,然後去調用方法,結果是展示商品的id和商品名稱

{% macro show_goods(id, name) %}
    商品id:{{ id }}
    商品名稱:{{ name }}
{% endmacro %}

{{ show_goods('1', '娃哈哈') }}
<br>
{{ show_goods('2', '雪碧') }}

例子2:

在index.html頁面中定義一個say()方法,然後解析該方法:

{% macro say() %}

    <h3>今天天氣氣溫回升</h3>
    <h3>適合去游泳</h3>
    <h3>適合去郊遊</h3>

{% endmacro %}

{{ say() }}

例子3:

定義一個function.html中定義一個方法:

{% macro create_user(name) %}
    創建了一個用戶:{{ name }}
{% endmacro %}

在index.html中引入function.html中定義的方法

{% from 'functions.html' import create_user %}

{{ create_user('小花') }}

2.3 循環

{% for item in cols %}

    aa

{% else %}

    bb

{% endfor %}

也可以獲取循環信息loop

loop.first

loop.last

loop.index

loop.revindex

例子:

在視圖中定義一個視圖函數:

@stu.route('/scores/')
def scores():

    scores_list = [21,34,32,67,89,43,22,13]

    content_h2 = '<h2>今天你們真帥</h2>'
    content_h3 = '   <h3>今天你們真帥</h3>   '

    return render_template('scores.html',
                           scores=scores_list,
                           content_h2=content_h2,
                           content_h3=content_h3)

(該視圖函數,在下面講解的過濾器中任然使用其返回的content_h2等參數)

首先: 在頁面中進行解析scores的列表。題目要求:第一個成績展示爲紅色,最後一個成績展示爲綠色,其他的不變

<ul>
   {% for score in scores %}
        {% if loop.first %}
            <li style="color:red;">{{ loop.revindex }}:{{ loop.index }}:{{ score }}</li>
        {% elif loop.last %}
            <li style="color:green;">{{ loop.revindex }}:{{ loop.index }}:{{ score }}</li>
        {% else %}
            <li> {{ loop.revindex }}:{{ loop.index }}:{{ score }}</li>
        {% endif %}
    {% endfor %}
</ul>

2.4 過濾器

語法:

{{ 變量|過濾器|過濾器... }}

capitalize 單詞首字母大寫

lower 單詞變爲小寫

upper 單詞變爲大寫

title

trim 去掉字符串的前後的空格

reverse 單詞反轉

format

striptags 渲染之前,將值中標籤去掉

safe 講樣式渲染到頁面中

default

last 最後一個字母

first

length

sum

sort

例子:

<ul>
    <li>{{ content_h2 }}</li>
    <li>{{ content_h2|safe }}</li>
    <li>{{ content_h2|striptags }}</li>

    <li>{{ content_h3 }}</li>
    <li>{{ content_h3|length }}</li>
    <li>{{ content_h3|trim|safe }}</li>
    <li>{{ content_h3|trim|length }}</li>
</ul>

3. 定義模板

3.1 定義基礎模板base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        {% block title %}
        {% endblock %}
    </title>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>

    {% block extCSS %}
    {% endblock %}
</head>
<body>

{% block header %}
{% endblock %}

{% block content%}
{% endblock %}

{% block footer%}
{% endblock %}

{% block extJS %}
{% endblock %}

</body>
</html>

3.2 定義基礎模板base_main.html

{% extends 'base.html' %}

{% block extCSS %}
    <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
{% endblock %}

4. 靜態文件信息配置

<b>django</b>:

第一種方式:

{% load static %}
<link rel="stylesheet" href="{% static 'css/index.css' %}">

第二種方式:

<link rel="stylesheet" href="/static/css/index.css">

<b>flask</b>:

第一種方式:

<link rel="stylesheet" href="/static/css/index.css">

第二種方式:

<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">

flask使用操作指南之模型1


1. Flask模型

Flask默認並沒有提供任何數據庫操作的API

我們可以選擇任何適合自己項目的數據庫來使用

Flask中可以自己的選擇數據,用原生語句實現功能,也可以選擇ORM(SQLAlchemy,MongoEngine)

SQLAlchemy是一個很強大的關係型數據庫框架,支持多種數據庫後臺。SQLAlchemy提供了高層ORM,也提供了使用數據庫原生SQL的低層功能。

ORM:

將對對象的操作轉換爲原生SQL
優點
    易用性,可以有效減少重複SQL
    性能損耗少
    設計靈活,可以輕鬆實現複雜查詢
    移植性好

針對於Flask的支持,官網地址

pip install flask-sqlalchemy

安裝驅動

pip install pymysql

2. 定義模型

使用SQLALchemy的對象去創建字段

其中tablename指定創建的數據庫的名稱

創建models.py文件,其中定義模型

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()


class Student(db.Model):

    s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    s_name = db.Column(db.String(16), unique=True)
    s_age = db.Column(db.Integer, default=1)

    __tablename__ = "student"

其中:

Integer表示創建的s_id字段的類型爲整形,

primary_key表示是否爲主鍵

String表示該字段爲字符串

unique表示該字段唯一

default表示默認值

autoincrement表示是否自增

3. 創建數據表

在視圖函數中我們引入models.py中定義的db

from App.models import db

@blue.route("/createdb/")
def create_db():
    db.create_all()
    return "創建成功"

@blue.route('/dropdb/')
def drop_db():
    db.drop_all()
    return '刪除成功'

其中: db.create_all()表示創建定義模型中對應到數據庫中的表

db.drop_all()表示刪除數據庫中的所有的表

4. 初始化SQLALchemy

在定義的init.py文件中使用SQLALchemy去整合一個或多個Flask的應用

有兩種方式:

第一種:

from flask_sqlalchemy import SQLALchemy

app = Flask(__name__)
db = SQLAlchemy(app)

第二種:

from App.models import db

def create_app():
    app = Flask(__name__)
    db.init_app(app)
    return app

5. 配置數據庫的訪問地址

官網配置參數

數據庫連接的格式:

dialect+driver://username:password@host:port/database

dialect數據庫實現

driver數據庫的驅動

例子:
訪問mysql數據庫,驅動爲pymysql,用戶爲root,密碼爲123456,數據庫的地址爲本地,端口爲3306,數據庫名稱HelloFlask

設置如下: "mysql+pymysql://root:123456@localhost:3306/HelloFlask"

在初始化init.py文件中如下配置:

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:123456@localhost:3306/HelloFlask"

6. 對學生數據進行CRUD操作

語法:

類名.query.xxx

獲取查詢集:

all()

filter(類名.屬性名==xxx)

filter_by(屬性名=xxx)

數據操作:

在事務中處理,數據插入

db.session.add(object)

db.session.add_all(list[object])

db.session.delete(object)

db.session.commit()

修改和刪除基於查詢

6.1 想學生表中添加數據

@blue.route('/createstu/')
def create_stu():

    s = Student()
    s.s_name = '小花%d' % random.randrange(100)
    s.s_age = '%d' % random.randrange(30)

    db.session.add(s)
    db.session.commit()

    return '添加成功'

提交事務,使用commit提交我們的添加數據的操作

6.2 獲取所有學生信息

將學生的全部信息獲取到,並且返回給頁面,在頁面中使用for循環去解析即可

@blue.route("/getstudents/")
def get_students():
    students = Student.query.all()
    return render_template("StudentList.html", students=students)

6.3 獲取s_id=1的學生的信息

寫法1:

students = Student.query.filter(Student.s_id==1)

寫法2:

students = Student.query.filter_by(s_id=2)

注意:filter中可以接多個過濾條件

寫法3:

sql = 'select * from student where s_id=1'
students = db.session.execute(sql)

6.4 修改學生的信息

寫法1:

students = Student.query.filter_by(s_id=3).first()
students.s_name = '哈哈'
db.session.commit()

寫法2:

Student.query.filter_by(s_id=3).update({'s_name':'娃哈哈'})
 
db.session.commit()

6.5 刪除一個學生的信息

寫法1:

students = Student.query.filter_by(s_id=2).first()
db.session.delete(students)
db.session.commit()

寫法2:

students = Student.query.filter_by(s_id=1).all()
db.session.delete(students[0])
db.session.commit()

注意:filter_by後的結果是一個list的結果集

<b>重點注意:在增刪改中如果不commit的話,數據庫中的數據並不會更新,只會修改本地緩存中的數據,所以一定需要db.session.commit()</b>

flask使用操作指南之模型2


1. 深入數據庫增刪改查

定義模型,並定義初始化的函數:

class Student(db.Model):

    s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    s_name = db.Column(db.String(16), unique=True)
    s_age = db.Column(db.Integer, default=1)

    __tablename__ = "student"

    def __init__(self, name, age):
        self.s_name = name
        self.s_age = age

1.1 增--批量增加

第一種方式:

@blue.route('/createstus/')
def create_users():
    stus = []
    for i in range(5):
        # 實例化Student的對象
        s = Student()
        # 對象的屬性賦值
        s.s_name = '張三%s' % random.randrange(10000)
        s.s_age = '%d' % random.randrange(100)
        stus.append(s)
    # 添加需要創建的數據
    db.session.add_all(stus)
    # 提交事務到數據庫
    db.session.commit()

    return '創建成功'

注:在創建單條數據的時候使用db.session.add(),在創建多條數據的時候使用db.session.add_all()

第二種方式:

@blue.route('/createstus/')
def create_users():
    stus = []
    for i in range(5):
        # 使用類的初始化去創建Student對象
        s = Student('張三%s' % random.randrange(10000),
                    '%d' % random.randrange(100))
        stus.append(s)

    db.session.add_all(stus)
    db.session.commit()

    return '創建成功'

1.2 查--使用運算符

獲取查詢集

filter(類名.屬性名.運算符(‘xxx’))

filter(類名.屬性 數學運算符  值)

運算符:

contains: 包含
startswith:以什麼開始
endswith:以什麼結束
in_:在範圍內
like:模糊
__gt__: 大於
__ge__:大於等於
__lt__:小於
__le__:小於等於

篩選:

offset()

limit()

order_by()

get()

first()

paginate()

邏輯運算:

與
    and_
    filter(and_(條件),條件…)

或
    or_
    filter(or_(條件),條件…)

非
    not_
    filter(not_(條件),條件…)

例子1:

  1. 查詢學生的id爲3,4,5,6,16的的學生信息,使用<b>in_邏輯運算</b>
    @blue.route('/getstubyids/')
    def get_stu_by_ids():

        students = Student.query.filter(Student.s_id.in_([3,4,5,6,16]))
        return render_template('StudentList.html', students=students)
  1. 查詢學生的年齡小於18歲的學生的信息

     Student.query.filter(Student.s_age < 18)
    
  2. 查詢學生的年齡小於18歲的學生的信息,<b>__lt__小於</b>

     students = Student.query.filter(Student.s_age.__lt__(15))
    
  3. 查詢學生的年齡小於等於18歲的學生的信息,<b>__le__小於等於</b>

     students = Student.query.filter(Student.s_age.__le__(15))
    
  4. 查詢學生的姓名以什麼開始或者以什麼結尾的學生的信息<b>startswith和endswith</b>

     students = Student.query.filter(Student.s_name.startswith('張'))
     students = Student.query.filter(Student.s_name.endswith('2'))
    
  5. 查詢id=4的學生的信息

     Student.query.get(4)
     獲取的結果是學生的對象
    
  6. 模糊搜索like

     %:代表一個或者多個
     _:代表一個
     
     Student.query.filter(Student.s_name.like('%張%')) 
    
  7. 分頁,查詢第二頁的數據4條

     第一個參數是那一頁,第二個參數是一頁的條數,第三個參數是是否輸出錯誤信息
     students = Student.query.paginate(2, 4, False).items
    

例子2:

跳過offset幾個信息,截取limit結果的幾個值

# 按照id降序排列
stus = Student.query.order_by('-s_id')

# 按照id升序排列
stus = Student.query.order_by('s_id')
stus = Student.query.order_by(asc('s_id'))
stus = Student.query.order_by('s_id asc')

# 按照id降序獲取三個
stus = Student.query.order_by('-s_id').limit(3)
stus = Student.query.order_by('s_id desc').limit(3)

from sqlalchemy import desc
stus = Student.query.order_by(desc('s_id')).limit(3)

# 獲取年齡最大的一個
stus = Student.query.order_by('-s_age').first()

# 跳過3個數據,查詢5個信息
stus = Student.query.order_by('-s_age').offset(3).limit(5)

# 跳過3個數據
stus = Student.query.order_by('-s_age').offset(3)

# 獲取id等於24的學生
stus = Student.query.filter(Student.s_id==24)
stus = Student.query.get(24)

例子3:

  1. 查詢

    from sqlalchemy import and_, or_, not_

    <b>查詢多個條件</b>

    stus = Student.query.filter(Student.s_age==18, Student.s_name=='雅典娜')

    <b>and_ 並且條件</b>

    stus = Student.query.filter(and_(Student.s_age==18, Student.s_name=='雅典娜'))

    <b>or_ 或者條件</b>

    stus = Student.query.filter(or_(Student.s_age==18, Student.s_name=='火神'))

    <b>not_ 非</b>

    stus = Student.query.filter(not_(Student.s_age==18), Student.s_name=='火神')

    查詢姓名不包含'可愛‘,並且年齡不等於12的學生

    stus = Student.query.filter(not_(Student.s_name.contains('可愛')),
    not_(Student.s_age == 12))

例子4:

<b>分頁:</b>


image.png

後端數據處理:

# 方法一:手動實現分頁,使用offset和limit
page = int(request.args.get('page', 1))
stus = Student.query.offset((page-1)*5).limit(5)

# 方法二: 使用切片[:]
s_page = (page - 1)*5
e_page = page * 5
stus = Student.query.all()[s_page: e_page]

# 方法三:使用paginate
# 查詢第幾頁的數據  
page = int(request.args.get('page', 1))

# 每一頁的條數多少,默認爲10條
per_page = int(request.args.get('per_page', 10))

# 查詢當前第幾個的多少條數據
paginate = Student.query.order_by('-s_id').paginate(page, per_page, error_out=False)

stus = paginate.items

前端數據展示:

<h2>學生信息</h2>
{% for stu in stus %}
    id:{{ stu.s_id }}
    姓名:{{ stu.s_name }}
    年齡:{{ stu.s_age }}
    <br>
{% endfor %}
<br>
總頁數: {{ paginate.pages }}
<br>
一共{{ paginate.total }}條數據
<br>
當前頁數:{{ paginate.page }}
<br>
{% if paginate.has_prev %}
    <a href="/stupage/?page={{ paginate.prev_num }}">上一頁</a>:{{ paginate.prev_num }}
{% endif %}

{% if paginate.has_next %}
    <a href="/stupage/?page={{ paginate.next_num }}">下一頁</a>:{{ paginate.next_num }}
{% endif %}
<br>

<br>
頁碼:{% for i in  paginate.iter_pages() %}
        <a href="/stupage/?page={{ i }}">{{ i }}</a>
    {% endfor %}

2. 關聯關係

2.1 一對多建立模型

學生模型:

class Student(db.Model):

    s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    s_name = db.Column(db.String(20), unique=True)
    s_age = db.Column(db.Integer, default=18)
    s_g = db.Column(db.Integer, db.ForeignKey('grade.g_id'), nullable=True)

    __tablename__ = 'student'

班級模型:

class Grade(db.Model):

    g_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    g_name = db.Column(db.String(10), unique=True)
    g_desc = db.Column(db.String(100), nullable=True)
    g_time = db.Column(db.Date, default=datetime.now)
    students = db.relationship('Student', backref='stu', lazy=True)

    __tablename__ = 'grade'

官網解釋有如下幾個lazy的參數:

lazy 決定了 SQLAlchemy 什麼時候從數據庫中加載數據:,有如下四個值:

<b>select</b>/True: (which is the default) means that SQLAlchemy will load the data as necessary in one go using a standard select statement.

<b>joined</b>/False: tells SQLAlchemy to load the relationship in the same query as the parent using a JOIN statement.

<b>subquery</b>: works like ‘joined’ but instead SQLAlchemy will use a subquery.

<b>dynamic</b>: is special and useful if you have many items. Instead of loading the items SQLAlchemy will return another query object which
you can further refine before loading the items. This is usually what you want if you expect more than a handful of items for this relationship

select就是訪問到屬性的時候,就會全部加載該屬性的數據。

joined則是在對關聯的兩個表進行join操作,從而獲取到所有相關的對象。

dynamic則不一樣,在訪問屬性的時候,並沒有在內存中加載數據,而是返回一個query對象, 需要執行相應方法纔可以獲取對象,

2.2

  1. 通過班級查詢學生信息
    @grade.route('/selectstubygrade/<int:id>/')
    
    def select_stu_by_grade(id):
        grade = Grade.query.get(id)
        # 通過班級對象.定義的relationship變量去獲取學生的信息
        stus = grade.students
    
        return render_template('grade_student.html',
                               stus=stus,
                               grade=grade
                               )
  1. 通過學生信息查詢班級信息
    @stu.route('/selectgradebystu/<int:id>/')

    def select_grade_by_stu(id):

        stu = Student.query.get(id)
        # 通過學生對象.定義的backref參數去獲取班級的信息
        grade = stu.stu
    
        return render_template('student_grade.html',
                               grade=grade,
                               stu=stu)

注意:表的外鍵由db.ForeignKey指定,傳入的參數是表的字段。db.relations它聲明的屬性不作爲表字段,第一個參數是關聯類的名字,backref是一個反向身份的代理,相當於在Student類中添加了stu的屬性。例如,有Grade實例dept和Student實例stu。dept.students.count()將會返回學院學生人數;stu.stu.first()將會返回學生的學院信息的Grade類實例。一般來講db.relationship()會放在一這一邊。

3. 數據庫遷移

在django中繼承了makemigrations,可以通過migrate操作去更新數據庫,修改我們定義的models,然後在將模型映射到數據庫中。

在flask中也有migrate操作,它能跟蹤模型的變化,並將變化映射到數據庫中

2.1 安裝migrate

pip install flask-migrate

2.2 配置使用migrate

2.2.1 初始化,使用app和db進行migrate對象的初始化
from flask_migrate import Migrate

#綁定app和數據庫
Migrate(app=app, db=db)
2.2.2 安裝了flask-script的話,可以在Manager()對象上添加遷移指令
from flask_migrate import Migrate, MigrateCommand

app = Flask(__name__)

manage = Manager(app=app)

manage.add_command('db', MigrateCommand)

操作:

python manage.py db init  初始化出migrations的文件,只調用一次

python manage.py db migrate  生成遷移文件

python manage.py db upgrade 執行遷移文件中的升級

python manage.py db downgrade 執行遷移文件中的降級

python manage.py db --help 幫助文檔

flask使用操作指南之模型3


1. 關聯關係---多對多

定義模型:

引入SLALchemy

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

創建中間表

sc = db.Table('sc',
    db.Column('s_id', db.Integer, db.ForeignKey('student.s_id'), primary_key=True),
    db.Column('c_id', db.Integer, db.ForeignKey('courses.c_id'), primary_key=True)
)

創建學生類Student

class Student(db.Model):

    s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    s_name = db.Column(db.String(20), unique=True)
    s_age = db.Column(db.Integer, default=18)
    s_g = db.Column(db.Integer, db.ForeignKey('grade.g_id'), nullable=True)

    __tablename__ = 'student'

    def __init__(self, name, age):

        self.s_name = name
        self.s_age = age
        self.s_g = None

創建課程表的模型,Course類

class Course(db.Model):

    c_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    c_name = db.Column(db.String(20), unique=True)
    students = db.relationship('Student',
                               secondary=sc,
                               backref='cou')

    __tablename__ = 'courses'

    def __init__(self, name):

        self.c_name = name

sc表由<font style="color:red;">db.Table聲明</font>,我們不需要關心這張表,因爲這張表將會由SQLAlchemy接管,它唯一的作用是作爲students表和courses表關聯表,所以必須在db.relationship()中指出<font style="color:red;">sencondary關聯表參數</font>。lazy是指查詢時的惰性求值的方式,這裏有詳細的參數說明,而db.backref是聲明反向身份代理,其中的lazy參數是指明反向查詢的惰性求值方式.

2. 添加學生和課程之間的關係

通過頁面中傳遞學生的id和課程的id,分別獲取學生的對象和課程的對象,在使用關聯關係append去添加學生對象,並且add以後再commit後,就可以在中間表sc中查看到新增的關聯關係了。

    userid = request.form.get('userid')
    courseid = request.form.get('courseid')

    stu = Student.query.get(userid)
    cou = Course.query.get(courseid)

    cou.students.append(stu)
    db.session.add(cou)
    db.session.commit()

3. 刪除學生和課程之間的關係

通過頁面獲取傳遞的學生的id和課程的id,分別獲取學生對象和課程對象,在使用關聯關係remove去刪除學生對象,並commit將事務提交到數據庫中

stu = Student.query.get(s_id)
cou = Course.query.get(c_id)

cou.students.remove(stu)
db.session.commit()

4. 通過課程查詢學生的信息

以下定義在課程course的模型中,所以通過課程查詢學生的信息,<font style="color:red;">語法爲課程的對象.studengs</font>。如果知道學生的信息反過來找課程的信息,則使用backref的反向關聯去查詢,<font style="color:red;">語語法爲學生的對象.cou(反向)</font>

students = db.relationship('Student',secondary=sc,backref='cou')

cou = Course.query.get(2)
stus = cou.students

5. 通過學生去查詢課程的信息

stu = Student.query.get(id)
cous = stu.cou

flask使用操作指南之插件


1. 開發,頁面調試工具debugtoolbar

1.1 安裝

pip install flask-debugtoolbar

1.2 配置

from flask import Flask

from flask_debugtoolbar import DebugToolbarExtension

app = Flask(__name__)

app.debug = True

app.config['SECRET_KEY'] = '<replace with a secret key>'

toolbar = DebugToolbarExtension(app)

2. restful

Flask-RESTful 提供的最主要的基礎就是資源(resources)。資源(Resources)是構建在 Flask 可拔插視圖 之上,只要在你的資源(resource)上定義方法就能夠容易地訪問多個 HTTP 方法

官網上描述了一個最簡單的restful風格的api,如下:

from flask import Flask
from flask.ext import restful

app = Flask(__name__)
api = restful.Api(app)

class HelloWorld(restful.Resource):
    def get(self):
        return {'hello': 'world'}

api.add_resource(HelloWorld, '/')

if __name__ == '__main__':
    app.run(debug=True) 

2.1 安裝

pip install flask_restful

2.2 配置

在create_app()獲取Flask(name)對象中,設置如下配置

from flask_restful import Api

api = Api()

api.init_app(app=app)

在views中需要引入配置的api還有Resource

# 導入包和restful中的Api對象
from flask_restful import Resource
from utils.functions import api

# 定義類,啓動包含了對數據處理的GET,POST,PATCH,PUT,DELETE請求
class CreateCourse(Resource):

def get(self, id):
    course = Course.query.get(id)
    return course.to_dict()

def post(self):

    courses = ['大學英語', '大學物理', '線性代數', '高數',
               'VHDL', 'ARM', '馬克思主義', '農場勞動']
    course_list = []
    for course in courses:
        c = Course()
        c.c_name = course
        course_list.append(c)
    db.session.add_all(course_list)
    db.session.commit()

    courses = Course.query.all()
    return [course.to_dict() for course in courses]

def patch(self, id):
    c_name = request.form.get('c_name')
    course = Course.query.get(id)
    course.c_name = c_name
    db.session.commit()
    return {'code': 200, 'data': course.to_dict(), 'msg': '請求成功'}

def delete(self, id):
    course = Course.query.get(id)
    db.session.delete(course)
    db.session.commit()
    return {'code': 200, 'msg': '刪除成功'}


# 綁定處理url
api.add_resource(CreateCourse, '/api/course/<int:id>/', '/api/course/')

2.3 端點(Endpoints)

在一個 API 中,你的資源可以通過多個 URLs 訪問。你可以把多個 URLs 傳給 Api 對象的 Api.add_resource() 方法。每一個 URL 都能訪問到你的 Resource

如:

api.add_resource(CreateCourse, '/api/course/<int:id>/', '/api/course/')

2.4 返回響應

Flask-RESTful 支持視圖方法多種類型的返回值。同 Flask 一樣,你可以返回任一迭代器,它將會被轉換成一個包含原始 Flask 響應對象的響應。Flask-RESTful 也支持使用多個返回值來設置響應代碼和響應頭

如:

def get(self, id):
    course = Course.query.get(id)
    return course.to_dict(), 200

Django和Flask區別:


1. jiaji2和DjangoTemplates模板引擎相比,jiaja2語法更簡單

比如: loop.index 和 forloop.counter
       loop.revindex 和 forloop.revcounter
jiaja2中沒有ifequal

2. 耦合

Django: 大而全,但是耦合性高。Auth,Permission,admin基本沒用
        開發快,符合MVC模式

Flask: 微框架,很小巧。需要哪些功能,自己裝。
        需要熟悉MVC模式

3. 模型

3.1 模型定義

1. 模型中不定義數據庫的表名:
    在django中默認表名爲:'應用app名_模型名小寫'
    在flask中默認的表名爲:'模型名小寫'

2. 自增id字段:
    在django中默認會創建自增的主鍵id
    在flask中需要自己寫自增的主鍵id:
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)

3. 查詢所有數據的結果,all()方法
    在django中查詢的結果爲QuerySet
    在Flask中查詢結果爲List

4. 查詢滿足條件的數據的結果,filter(), filter_by()方法
    在django中查詢的結果爲QuerySet
    在Flask中查詢結果爲BaseQuery objects

3.2 模型數據查詢

Django:

一對多:

  模型1: u 字段爲 FOREIGN_KEY,關聯到模型2
    模型1.u = u對象
    模型1.u_id = u對象.id


  模型1查找模型2的數據
    模型2對象=模型1對象.u
    模型1對象=模型2對象.模型1_set.all()

一對一:

  模型1查找模型2的數據
    模型2對象=模型1對象.u
    模型1對象=模型2對象.模型1.all()

Flask:

一對多:

    模型1: u字段爲FOREIGN KEY,關聯到模型2
    模型2: yy字段,定義relationship字段, backref=‘uu’

    模型1查找模型2:
        模型2對象 = 模型1對象.uu
        模型1對象 = 模型2對象.yy
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章