Flask快速上手及目標檢測服務接口&前端顯示示例

最簡單的Flask應用示例

創建一個flask實例,使用route構建路由,app.run開啓服務

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'
if __name__ == '__main__':
    app.run()

 

Flask相關知識點提要

路由

使用裝飾器把URL映射到視圖函數

@app.route('/')
def index():#視圖函數
    return 'Index Page'

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

可以在URL中添加變量,變量會作爲關鍵字參數傳遞給函數。使用<converter:variable_name>

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

URL構建

使用url_for()函數用於構建指定函數的URL。函數名是第一個參數。

沒把URL寫死在模板中,使用url_for()動態構建的好處:

描述性更好,直觀,避免相對路徑

from flask import Flask, escape, url_for

app = Flask(__name__)

@app.route('/')
def index():
    return 'index'

@app.route('/login')
def login():
    return 'login'

@app.route('/user/<username>')
def profile(username):
    return '{}\'s profile'.format(escape(username))

with app.test_request_context():
    print(url_for('index'))
    print(url_for('login'))
    print(url_for('login', next='/'))
    print(url_for('profile', username='John Doe'))

渲染模板

利用Jinja2模板引擎,使用render_template()方法渲染模板,只需要提供模板名稱和參數變量即可。模板統一放在template文件夾裏面。

 Jinjia2模板語法:

if語句:

{ % if 條件 %}
  語句1
{ % else %}
  語句2
{ % end if %}

 for循環:

{ % for 變量 in 容器 %}
  語句1
{ % end for %}

 註釋:

{ # 註釋 #}

from flask import render_template

@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
    return render_template('hello.html', name=name)

操作請求數據

客戶端網頁向服務器傳送的數據通過request對象來處理。在視圖函數中直接使用可以取到當前本次請求。

通過Method屬性可以操作當前請求方法,通過使用form屬性處理表單數據,使用file處理文件數據。

@app.route('/login', methods=['POST', 'GET'])
def login():
    error = None
    if request.method == 'POST':
        if valid_login(request.form['username'], #請求的form對象
                       request.form['password']):
            return log_the_user_in(request.form['username'])
        else:
            error = 'Invalid username/password'
    return render_template('login.html', error=error)
@app.route("/upload",methods = ['POST', 'GET'])
def upload():
    if request.method == "POST":
        f = request.files['file'] #請求文件
        basepath = os.path.dirname(__file__)
        f.save(basepath )

處理文件的時候需要在你的 HTML 表單中設置 enctype="multipart/form-data" 屬性。通過files屬性訪問上傳的文件,文件有一個保存的方法即save,可以保存到服務器。

重定向

使用redirect()進行重定向

from flask import abort, redirect, url_for

@app.route('/')
def index():
    return redirect(url_for('login'))

消息閃現

客戶端進行操作後,可以使用flash來閃現一個消息。

服務器代碼中使用flash("消息“),html中使用get_flashed_messages() 來操作消息

數據庫交互操作

使用Flask_SQLAlchemy進行對數據庫的抽象,不用直接寫SQL語句,使用python對象來操作數據庫。

①配置數據庫:

# 數據庫鏈接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:密碼@127.0.0.1:3306/test'
# 動態追蹤修改設置,如未設置只會提示警告
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

②終端創建數據庫:

create database test charset utf8;

③創建對象,添加模型,添加數據

db = SQLAlchemy(app)
#定義模型類即數據庫的一個表,模型要繼承自db.Model
class Authors(db.Model):
    __tablename__ = 'authors' #表名
    id = db.Column(db.Integer,primary_key=True) #表的屬性字段
    name = db.Column(db.String(64),unique=True)
    #關係,使用relationship描述兩個屬性的關係
    books = db.relationship('Books',backref = 'Authors')

class Books(db.Model):
    __tablename__ = 'books'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True, index=True)

    author_id = db.Column(db.Integer, db.ForeignKey('authors.id')) #外鍵

表之間的關係使用realtionship描述,例如上例Authors與Books的關係,realtionship中第一個參數爲對應參照的類,

第二個參數backref爲反向引用屬性。可以使用author.books來調用。

使用Flask-SQLAlchemy時,插入、修改、刪除操作,均由數據庫會話管理。

會話即db.session。常用的操作如下:

db.session.add(obj) #添加對象
db.session.add_all([obj1,obj2,..]) #添加多個對象
db.session.delete(obj) #刪除對象
db.session.commit() #提交會話
db.session.rollback() #回滾
db.session.remove() #移除會話
#添加示例,首先創建所有與db相關聯的表
db.create_all() au1
= Authors(name='張三') au2 = Authors(name='李四') db.session.add_all([au1, au2]) db.session.commit() bk1 = Books(name='linux', author_id=au1.id) bk2 = Books(name='python', author_id=au1.id) db.session.add_all([bk1, bk2]) db.session.commit()

④查詢數據:

#filter,需要寫模型.參數 == 判斷
User.query.filter(User.name=='wang').all()
#filter_by,直接寫對應參數 = 判斷
User.query.filter_by(name='wang').all()
#get,使用主鍵作爲參數
User.get(id)

綜合示例1

圖書管理系統,實現簡單的顯示增刪查

服務端代碼:

from flask import Flask, render_template, redirect, url_for, flash, request
from flask_sqlalchemy import SQLAlchemy
from flask_wtf.csrf import CSRFProtect
from flask_wtf import FlaskForm
from wtforms import StringField,SubmitField
from wtforms.validators import DataRequired


app = Flask(__name__)
#配置數據庫 app.config[
'SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:878698@localhost:3306/flask_books' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False CSRFProtect(app) app.config['SECRET_KEY'] = "jfkdjfkdkjf" #初始化數據庫對象 db = SQLAlchemy(app) #定義模型類,定義表名、字段、關係 class Authors(db.Model): __tablename__ = 'authors' id = db.Column(db.Integer,primary_key=True) name = db.Column(db.String(64),unique=True) books = db.relationship('Books',backref = 'Authors') class Books(db.Model): __tablename__ = 'books' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True, index=True) author_id = db.Column(db.Integer, db.ForeignKey('authors.id')) class Authorform(FlaskForm): author = StringField('作者',validators = [DataRequired()]) book = StringField('書名',validators = [DataRequired()]) submit = SubmitField('提交') #使用wtf表單顯示在網頁 @app.route('/') def view(): authors = Authors.query.all() author_form = Authorform() return render_template('index.html',authors=authors,form = author_form) #從表單位置增加數據 @app.route('/add_book',methods=['POST']) def add_book(): author_form = Authorform() author_name = author_form.author.data book_name = author_form.book.data # 校驗參數 if not all([author_name,book_name]): return "作者或者書籍爲空" author = Authors.query.filter_by(name = author_name).first() if author: book = Books.query.filter_by(name = book_name).first() if book: flash("已存在該書籍") else: bk = Books(name = book_name,author_id=author.id) db.session.add(bk) db.session.commit() else: at = Authors(name = author_name) db.session.add(at) db.session.commit() bk = Books(name=book_name, author_id=at.id) db.session.add(bk) db.session.commit() return redirect(url_for('view')) @app.route('/delete_book/<int:book_id>') def delete_book(book_id): book = Books.query.get(book_id) db.session.delete(book) db.session.commit() return redirect(url_for('view')) #重定向到view視圖函數顯示所有數據 @app.route('/delete_author/<int:author_id>') def delete_author(author_id): author = Authors.query.get(author_id) for bk in author.books: db.session.delete(bk) db.session.delete(author) db.session.commit() return redirect(url_for('view')) db.drop_all() db.create_all() au1 = Authors(name='李**') au2 = Authors(name='張**') db.session.add_all([au1, au2]) db.session.commit() bk1 = Books(name='linux', author_id=au1.id) bk2 = Books(name='python', author_id=au1.id) bk3 = Books(name='c++', author_id=au2.id) db.session.add_all([bk1, bk2, bk3]) db.session.commit() if __name__ == '__main__': app.run(debug=True)

HTML文件(index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>book</title>
</head>
<body>
    <h2>添加</h2>
    <form  action='/add_book' method="post">
        {{ form.csrf_token() }}
        {{ form.author.label }}{{ form.author }}<br>
        {{ form.book.label }}{{ form.book }}<br>
        {{ form.submit }}<br>
        {% for message in get_flashed_messages() %}
            <span style="color: red">{{ message }}</span>
        {% endfor %}
    </form>
    <h2>書籍展示</h2>
    <ul>

        {% for author in authors %}
            <li>作者:{{ author.name }}<a href="{{ url_for('delete_author',author_id=author.id) }}">刪除</a></li><br>
            <ul>
                {% for book in author.books %}
                    <li>書名:{{ book.name }} <a href="{{ url_for('delete_book',book_id=book.id) }}">刪除</a></li><br>
                {% endfor %}
            </ul>

        {% endfor %}

    </ul>
</body>
</html>

 

綜合示例2

圖像分類服務端接口,接收圖片文件送入模型識別

from flask import Flask, request
from werkzeug.utils import secure_filename
import uuid
from PIL import Image
import os
import torch
from torchvision.models import resnet18
from torchvision.transforms import ToTensor

app = Flask(__name__)
net = resnet18(pretrained=True)
net.eval()

@app.route("/",methods=["GET"])
def show():
    return "classifier api"

@app.route("/run",methods = ["GET","POST"])
def run():
    file = request.files['file'] #通過request對象獲取文件
    base_path = os.path.dirname(__file__)
    if not os.path.exists(os.path.join(base_path, "temp")):
        os.makedirs(os.path.join(base_path, "temp"))
    file_name = uuid.uuid4().hex
    upload_path = os.path.join(base_path, "temp", file_name)
    file.save(upload_path) #保存到服務器端

    img = Image.open(upload_path)
    img_tensor = ToTensor()(img).unsqueeze(0)
    out = net(img_tensor)
    pred = torch.argmax(out,dim = 1)
return "result_cls : {}".format(pred)

if __name__ == "__main__":
    app.run(host="0.0.0.0",port=5555,debug=True)

另一種接收base64格式轉存圖片的方式

from flask import request, Flask
import base64
import cv2
import numpy as np
app = Flask(__name__)
@app.route("/", methods=['POST','GET'])
def get_frame():
    # base64編碼轉爲圖片並保存
    # 傳輸的base64編碼爲轉換後整個值中data:image/jpg;base64,後的值
    img = base64.b64decode(str(request.form['image']).split('base64,')[-1])
    image_data = np.fromstring(img, np.uint8)
    image_data = cv2.imdecode(image_data, cv2.IMREAD_COLOR)
    cv2.imwrite('base64_2_img_01.png', image_data)
    print(image_data)

    return 'koukou'
if __name__ == "__main__":
    app.run("0.0.0.0", port=5005)

 

綜合示例3

圖片文件上傳,提供目標檢測算法接口及可視化界面

服務端代碼:

from flask import Flask, render_template, request, redirect, url_for, make_response, jsonify
from werkzeug.utils import secure_filename
import os,time
from datetime import timedelta
from main_demo import detect_cv2
ALLOWED_EXTENSIONS = set(["png","jpg","JPG","PNG", "bmp"])

def is_allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS

app = Flask(__name__)

# 靜態文件緩存過期時間
app.send_file_max_age_default = timedelta(seconds=1)

@app.route("/upload",methods = ['POST', 'GET'])
def upload():
    if request.method == "POST":
        f = request.files['file']
        if not ( f and is_allowed_file(f.filename)):
            return jsonify({
                "error":1001, "msg":"請檢查上傳的圖片類型,僅限於png、PNG、jpg、JPG、bmp"
            })
        basepath = os.path.dirname(__file__)
        upload_path = os.path.join(basepath, "static/images",secure_filename(f.filename))
        f.save(upload_path)

        #config
        cfg_file = 'pytorch-YOLOv4-master/cfg/yolov4.cfg'
        weightfile = 'pytorch-YOLOv4-master/checkpoints/yolov4.pth'
        imgfile = upload_path
        detected_path = os.path.join(basepath, "static/images", "output" + secure_filename(f.filename))

        #run & save
        detect_cv2(cfg_file, weightfile, imgfile, detected_path)
        # run(upload_path, conf, detected_path)

        # return render_template("upload_ok.html", userinput = user_input, val1=time.time(), path = detected_path)
        path = "./images/" + "output" + secure_filename(f.filename)
        return render_template("upload_ok.html", path = path, val1 = time.time()) #渲染模板,顯示圖片檢測結果
    return render_template("upload.html")


if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5555, debug=True)

HTML文件1(upload.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask上傳圖片演示</title>
</head>
<body>
    <h1>使用Flask上傳本地圖片</h1>
    <form action="" enctype='multipart/form-data' method='POST'>
        <input type="file" name="file" style="margin-top:20px;"/>
        <br>
        <input type="submit" value="上傳" class="button-new" style="margin-top:15px;"/>
    </form>

</body>
</html>

 

HTML文件2(upload_ok.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask上傳圖片演示</title>
</head>
<body>
    <h1>使用Flask上傳本地圖片</h1>
    <form action="" enctype='multipart/form-data' method='POST'>
        <input type="file" name="file" style="margin-top:20px;"/>
        <br>
        <input type="submit" value="上傳" class="button-new" style="margin-top:15px;"/>
    </form>
    <img src="{{ url_for('static', filename= path,_t=val1) }}" width="400" height="400" alt="圖片識別失敗"/>
</body>
</html>

 

 參考:

官方文檔

黑馬程序員教學

深度學習部署案例

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章