国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

基于 flask-socketio 的 CRUD 操作初探

K_B_Z / 1883人閱讀

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

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

HTTP 協(xié)議只能通過(guò)客戶端發(fā)起請(qǐng)求來(lái)與客戶端進(jìn)行通訊 —— 這是一個(gè)缺陷。

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

websocket 協(xié)議特性

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

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

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

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

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

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

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

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

flask-wtf-crud/
|-- env/
    |-- 
|-- app/ <項(xiàng)目的模塊名稱>
    |-- crud/ <前端藍(lán)圖>
        |-- __init__.py
        |-- views.py <路由和視圖函數(shù)文件>
        |-- forms.py <表單類文件, wtforms插件必須項(xiàng)>
        |-- templates 
            |-- static <靜態(tài)文件夾>
                |-- js 
                    |-- crud.js # 異步請(qǐng)求的程序主要在此添加
    |-- XXXXXX/ <其它藍(lán)圖>
    |-- __init__.py
    |-- models.py <數(shù)據(jù)庫(kù)模型文件>
|-- migrations/ <數(shù)據(jù)庫(kù)表關(guān)系文件夾,Flask-Migrate遷移數(shù)據(jù)庫(kù)時(shí)使用>
|-- config.py <項(xiàng)目的配置文件>
|-- manage.py <用于啟動(dòng)程序以及其它程序任務(wù)>
將 flask-socketio 引入項(xiàng)目 修改 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)容

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

    return app
當(dāng)前藍(lán)圖的 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ù)端自動(dòng)發(fā)送通信請(qǐng)求 """
    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ā)送的通信請(qǐng)求 """

    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)頁(yè),會(huì)顯示服務(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ù)庫(kù)里 增加刪改 內(nèi)容的時(shí)候,表格的內(nèi)容沒(méi)有變化——盡管局部已經(jīng)進(jìn)行了刷新。要想顯示變化后的數(shù)據(jù)庫(kù)內(nèi)容,必須得重新啟動(dòng)一下 flask 服務(wù)。

就整體的部署來(lái)說(shuō),在 flask 項(xiàng)目里添加 websocket 協(xié)議,顯得項(xiàng)目較重,實(shí)現(xiàn)一個(gè)局部刷新的功能還是用 ajax 比較簡(jiǎn)單。

歡迎大俠能夠給我的項(xiàng)目提出修改意見(jiàn),先行感謝!?。?/p>

源碼下載

參考

基于 flask 的 CRUD 操作

WebSocket 教程 —— 阮一峰

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/44491.html

相關(guān)文章

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

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

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

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

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

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

    microelec 評(píng)論0 收藏0
  • angular開發(fā)中問(wèn)題記錄--啟動(dòng)過(guò)程初探

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

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

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

    godiscoder 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

K_B_Z

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<