成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

基于 flask-socketio 的 CRUD 操作初探

K_B_Z / 1891人閱讀

摘要:理解協(xié)議協(xié)議只能通過客戶端發(fā)起請求來與客戶端進行通訊這是一個缺陷。與協(xié)議有著良好的兼容性。以下的表格內(nèi)容顯示數(shù)據(jù)局里的內(nèi)容,每秒局部刷新一次表格內(nèi)容。歡迎大俠能夠給我的項目提出修改意見,先行感謝源碼下載參考基于的操作教程阮一峰

Flask 作為一個全棧架構(gòu),如果你只會 python,而不懂 javascript 的前端知識,似乎是無法支撐起你的 web 夢想的,比如,一個簡單的頁面 局部刷新 功能,你就需要用到 ajax 的知識,當(dāng)然,你還可以使用 HTML5 的新特性 —— websocket功能,好在 flask 還提供了一個 flask-socketio 插件,本文我們就探討一下這個 flask-scoketio插件的用法。
理解 websocket 協(xié)議

HTTP 協(xié)議只能通過客戶端發(fā)起請求來與客戶端進行通訊 —— 這是一個缺陷。

通過websocket 協(xié)議,服務(wù)器可以主動向客戶端推送信息,客戶端也可以主動向服務(wù)器發(fā)送信息,是真正的雙向平等對話,屬于服務(wù)器推送技術(shù)的一種。

websocket 協(xié)議特性

建立在 TCP 協(xié)議之上,服務(wù)器端的實現(xiàn)比較容易。

與 HTTP 協(xié)議有著良好的兼容性。默認(rèn)端口也是80和443,并且握手階段采用 HTTP 協(xié)議,因此握手時不容易屏蔽,能通過各種 HTTP 代理服務(wù)器。

數(shù)據(jù)格式比較輕量,性能開銷小,通信高效。

可以發(fā)送文本,也可以發(fā)送二進制數(shù)據(jù)。

沒有同源限制,客戶端可以與任意服務(wù)器通信。

協(xié)議標(biāo)識符是ws(如果加密,則為wss),服務(wù)器網(wǎng)址就是 URL。

使用 flask-socketio 安裝插件
pip install flask-socketio
項目結(jié)構(gòu)

本文是在 《基于 flask 的 CRUD 操作》 的基礎(chǔ)上增加了 webscoket 的功能,使用的是 init_app() 的形式加載 flask-socketio 插件,和網(wǎng)上的大多數(shù)教程稍有不同。

flask-wtf-crud/
|-- env/
    |-- 
|-- app/ <項目的模塊名稱>
    |-- crud/ <前端藍圖>
        |-- __init__.py
        |-- views.py <路由和視圖函數(shù)文件>
        |-- forms.py <表單類文件, wtforms插件必須項>
        |-- templates 
            |-- static <靜態(tài)文件夾>
                |-- js 
                    |-- crud.js # 異步請求的程序主要在此添加
    |-- XXXXXX/ <其它藍圖>
    |-- __init__.py
    |-- models.py <數(shù)據(jù)庫模型文件>
|-- migrations/ <數(shù)據(jù)庫表關(guān)系文件夾,Flask-Migrate遷移數(shù)據(jù)庫時使用>
|-- config.py <項目的配置文件>
|-- manage.py <用于啟動程序以及其它程序任務(wù)>
將 flask-socketio 引入項目 修改 manage.py 內(nèi)容
# -*- coding:utf-8 -*-
__author__ = "東方鶚"
__blog__ = u"http://www.os373.cn"

import os
from app import create_app, db, socketio
from app.models import User
from flask_script import Manager, Shell
from flask_migrate import Migrate, MigrateCommand


app = create_app(os.getenv("FLASK_CONFIG") or "default")
manager = Manager(app=app)
migrate = Migrate(app=app, db=db)

def make_shell_context():
    return dict(app=app, db=db, User=User)


manager.add_command("shell", Shell(make_context=make_shell_context))
manager.add_command("db", MigrateCommand)
manager.add_command("run", socketio.run(app=app, host="0.0.0.0", port=5001)) # 新加入的內(nèi)容


if __name__ == "__main__":
    manager.run()
 修改 app/__init__.py 內(nèi)容
# -*- coding:utf-8 -*-
__author__ = "東方鶚"
__blog__ = u"http://www.os373.cn"

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import config
from flask_socketio import SocketIO # 新加入的內(nèi)容
db = SQLAlchemy()

async_mode = None
socketio = SocketIO()


def create_app(config_name):
    """ 使用工廠函數(shù)初始化程序?qū)嵗?""
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app=app)

    db.init_app(app=app)

    socketio.init_app(app=app, async_mode=async_mode) # 新加入的內(nèi)容

    # 注冊藍本crud
    from .crud import crud as crud_blueprint
    app.register_blueprint(crud_blueprint, url_prefix="/crud")

    return app
當(dāng)前藍圖的 views.py
# -*- coding:utf-8 -*-
__author__ = "東方鶚"
__blog__ = u"http://www.os373.cn"

from flask import render_template, redirect, request, current_app, url_for, flash, json
from . import crud
from ..models import User
from .forms import AddUserForm, DeleteUserForm, EditUserForm
from ..import db
from threading import Lock
from app import socketio # 新加入的內(nèi)容
from flask_socketio import emit # 新加入的內(nèi)容

# 新加入的內(nèi)容-開始
thread = None
thread_lock = Lock()

def background_thread(users_to_json):
    """Example of how to send server generated events to clients."""
    while True:
        socketio.sleep(5)  每五秒發(fā)送一次

        socketio.emit("user_response", {"data": users_to_json}, namespace="/websocket/user_refresh")
# 新加入的內(nèi)容-結(jié)束

@crud.route("/", methods=["GET", "POST"])
def index():

    return render_template("index.html")


@crud.route("/websocket", methods=["GET", "POST"])
def websocket():
    add_user_form = AddUserForm(prefix="add_user")
    delete_user_form = DeleteUserForm(prefix="delete_user")
    if add_user_form.validate_on_submit():
        if add_user_form.role.data == u"True":
            role = True
        else:
            role = False
        if add_user_form.status.data == u"True":
            status = True
        else:
            status = False
        u = User(username=add_user_form.username.data.strip(), email=add_user_form.email.data.strip(),
                 role=role, status=status)
        db.session.add(u)
        flash({"success": u"添加用戶<%s>成功!" % add_user_form.username.data.strip()})
    if delete_user_form.validate_on_submit():
        u = User.query.get_or_404(int(delete_user_form.user_id.data.strip()))
        db.session.delete(u)
        flash({"success": u"刪除用戶<%s>成功!" % u.username})

    users = User.query.all()

    return render_template("websocket.html", users=users, addUserForm=add_user_form, deleteUserForm=delete_user_form)


@crud.route("/websocket-edit/", methods=["GET", "POST"])
def user_edit(user_id):
    user = User.query.get_or_404(user_id)
    edit_user_form = EditUserForm(prefix="edit_user", obj=user)
    if edit_user_form.validate_on_submit():
        user.username = edit_user_form.username.data.strip()
        user.email = edit_user_form.email.data.strip()
        if edit_user_form.role.data == u"True":
            user.role = True
        else:
            user.role = False
        if edit_user_form.status.data == u"True":
            user.status = True
        else:
            user.status = False
        flash({"success": u"用戶資料已修改成功!"})
        return redirect(url_for(".basic"))

    return render_template("edit_websocket.html", editUserForm=edit_user_form, user=user)

# 新加入的內(nèi)容-開始
@socketio.on("connect", namespace="/websocket/user_refresh")
def connect():
    """ 服務(wù)端自動發(fā)送通信請求 """
    global thread
    with thread_lock:
        users = User.query.all()
        users_to_json = [user.to_json() for user in users]

        if thread is None:
            thread = socketio.start_background_task(background_thread, (users_to_json, ))
    emit("server_response", {"data": "試圖連接客戶端!"})


@socketio.on("connect_event", namespace="/websocket/user_refresh")
def refresh_message(message):
    """ 服務(wù)端接受客戶端發(fā)送的通信請求 """

    emit("server_response", {"data": message["data"]})
# 新加入的內(nèi)容-結(jié)束

---------- 以上內(nèi)容是后端的內(nèi)容,以下內(nèi)容是將是前段的內(nèi)容 ----------

crud.js 內(nèi)容
$(document).ready(function () {
    namespace="/websocket/user_refresh";
    var socket = io.connect(location.protocol + "http://" + document.domain + ":" + location.port + namespace);
    $("#url_show").text("websocket URL: " + location.protocol + "http://" + document.domain + ":" + location.port + namespace);

    socket.on("connect", function() { // 發(fā)送到服務(wù)器的通信內(nèi)容
        socket.emit("connect_event", {data: "我已連接上服務(wù)端!"});
    });

    socket.on("server_response", function(msg) {
         顯示接受到的通信內(nèi)容,包括服務(wù)器端直接發(fā)送的內(nèi)容和反饋給客戶端的內(nèi)容
        $("#log").append("
" + $("
").text("接收 : " + msg.data).html()); }); socket.on("user_response", function(msg) { //console.log(eval(msg.data[0])); //$("#users_show").append("
" + $("
").text("接收 : " + msg.data).html()); var tbody = ""; var obj = eval(msg.data[0]); $.each(obj, function (n, value) { var role = ""; if (value.role===true){ role = "管理員"; }else { role = "一般用戶"; } var status = ""; if (value.status===true){ status = "正常"; }else { status = "注銷"; } edit_url = " 修改"; delete_url = "刪除"; var trs = ""; trs += "" + (n+1) + "" + value.username + "" + value.email + "" + role + "" + status + "" + edit_url + " | " + delete_url +""; tbody += trs; }) $("#users_show").empty(); $("#users_show").append(tbody); }); });
顯示結(jié)果

每次打開網(wǎng)頁,會顯示服務(wù)端發(fā)送的內(nèi)容——“試圖連接客戶端!”,其后,客戶端返回給服務(wù)端——“我已連接上服務(wù)端!”,而后又被服務(wù)端返回給客戶端顯示。

以下的表格內(nèi)容顯示數(shù)據(jù)局里的內(nèi)容,每 5 秒局部刷新一次表格內(nèi)容。

服務(wù)器后端 log 日志內(nèi)容如下:

總結(jié)

由于 flask 架構(gòu)具有上下文的限制,在數(shù)據(jù)庫里 增加刪改 內(nèi)容的時候,表格的內(nèi)容沒有變化——盡管局部已經(jīng)進行了刷新。要想顯示變化后的數(shù)據(jù)庫內(nèi)容,必須得重新啟動一下 flask 服務(wù)。

就整體的部署來說,在 flask 項目里添加 websocket 協(xié)議,顯得項目較重,實現(xiàn)一個局部刷新的功能還是用 ajax 比較簡單。

歡迎大俠能夠給我的項目提出修改意見,先行感謝!!!

源碼下載

參考

基于 flask 的 CRUD 操作

WebSocket 教程 —— 阮一峰

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/44491.html

相關(guān)文章

  • 利用K8S技術(shù)棧打造個人私有云(連載之:K8S資源控制)

    摘要:將用戶命令通過接口傳送給,從而進行資源的增刪改等操作。要使用編寫應(yīng)用程序,當(dāng)下大多語言都可以很方便地去實現(xiàn)請求來操作的接口從而控制和查詢資源,但本文主要是利用已有的客戶端來更加優(yōu)雅地實現(xiàn)的資源控制。 showImg(https://segmentfault.com/img/remote/1460000013517345); 【利用K8S技術(shù)棧打造個人私有云系列文章目錄】 利用K8S...

    Reducto 評論0 收藏0
  • 利用K8S技術(shù)棧打造個人私有云(連載之:K8S資源控制)

    摘要:將用戶命令通過接口傳送給,從而進行資源的增刪改等操作。要使用編寫應(yīng)用程序,當(dāng)下大多語言都可以很方便地去實現(xiàn)請求來操作的接口從而控制和查詢資源,但本文主要是利用已有的客戶端來更加優(yōu)雅地實現(xiàn)的資源控制。 showImg(https://segmentfault.com/img/remote/1460000013517345); 【利用K8S技術(shù)棧打造個人私有云系列文章目錄】 利用K8S...

    Render 評論0 收藏0
  • 基于websocketcelery任務(wù)狀態(tài)監(jiān)控

    摘要:目的曾經(jīng)想向前臺實時返回任務(wù)的狀態(tài)監(jiān)控,也查看了很多博客,但是好多也沒能如愿,因此基于網(wǎng)上已有的博客已經(jīng)自己的嘗試,寫了一個小的,實現(xiàn)前臺實時獲取后臺傳輸?shù)娜蝿?wù)狀態(tài)。實現(xiàn)仿照其他例子實現(xiàn)了一個簡單的后臺任務(wù)監(jiān)控。 1. 目的曾經(jīng)想向前臺實時返回Celery任務(wù)的狀態(tài)監(jiān)控,也查看了很多博客,但是好多也沒能如愿,因此基于網(wǎng)上已有的博客已經(jīng)自己的嘗試,寫了一個小的demo,實現(xiàn)前臺實時獲取后...

    microelec 評論0 收藏0
  • angular開發(fā)中問題記錄--啟動過程初探

    摘要:然而代碼的最終執(zhí)行結(jié)果表明,內(nèi)的代碼運行應(yīng)該是先于里面的代碼。項目中請求服務(wù)端異步獲取數(shù)據(jù)的接口參考文檔中幾種的區(qū)別源碼閱讀啟動過程 公司一些管理后臺的前端頁面,使用的是angular開發(fā)的,得益于angular的雙向綁定和模塊化controller使得構(gòu)建pc端的CRUD應(yīng)用簡單了不少。angular有很多比較難理解的概念,上手起來沒有vue簡單,不過對著模板項目、看看tutoria...

    G9YH 評論0 收藏0
  • Babylon-AST初探-實戰(zhàn)

    摘要:生成屬性這一步,我們要先提取原函數(shù)中的的對象。所以這里我們還是主要使用來訪問節(jié)點獲取第一級的,也就是函數(shù)體將合并的寫法用生成生成生成插入到原函數(shù)下方刪除原函數(shù)程序輸出將中的屬性提升一級這里遍歷中的屬性沒有再采用,因為這里結(jié)構(gòu)是固定的。 ??經(jīng)過之前的三篇文章介紹,AST的CRUD都已經(jīng)完成。下面主要通過vue轉(zhuǎn)小程序過程中需要用到的部分關(guān)鍵技術(shù)來實戰(zhàn)。 下面的例子的核心代碼依然是最簡單...

    godiscoder 評論0 收藏0

發(fā)表評論

0條評論

K_B_Z

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<