flask框架第三方組件

flask框架第三方組件

flask-session

第三方session,將session存入本地數據庫中。
需要導入原session,原理是替換原session中open-session函數,相當於重寫內容session

from flask import Flask,session
from flask_session import Session
from redis import Redis

app = Flask(__name__)
app.secret_key = "helloworld"

Session(app)
app.config["SESSION_TYPE"]="redis"  #設置數據庫類型
app.config["SESSION_REDIS"] = Redis(host="127.0.0.1",port=6379,db=1)  #設置數據庫屬性
@app.route('/')
def hello_world():
    if not session.get("IS_LOGINED"):
        return "沒有權限訪問"
    return 'Hello World!'
    
class Login(views.MethodView):
    def get(self):
        return render_template("login.html")

    def post(self):
        user = request.form.get("username")
        passwd = request.form.get("password")
        print(user)
        print(passwd)
        if user == "alex" and passwd == "123":
            session["IS_LOGINED"] = "True"
            return "登錄成功"
        else:
            msg = "用戶名或密碼錯誤"
            return render_template("login.html",msg=msg)
app.add_url_rule("/login",endpoint="login",view_func=Login.as_view(name="login"))

使用方法同原生session一樣
flask-session現在在cookie存放的session不再是數據,而是uuid
在redis中數據格式爲
key:前綴+uuid
value:session鍵值對
redis數據庫一般存放在內網服務器中,數據存放在內存中

WTForms

相當於modelsForm,類似於ORM
register_forms.py

from wtforms.fields import simple,core
from wtforms import Form
from wtforms import validators

class RegisterForm(Form):
    username = simple.StringField(
        label="用戶名",
        validators=[
            validators.DataRequired(message="數據不能爲空"),
            validators.Length(min=4,max=16,message="大於4位小於16位")
        ],
        render_kw={"class":"form-control"}  # 生成標籤時,添加class
    )
    password = simple.PasswordField(
        label="密碼",
        validators = [
            validators.DataRequired(message="密碼不能爲空"),
            validators.Length(min=4,max=16,message="大於4位小於16位"),
            validators.Regexp(regex="\w+",message="密碼必須爲數字,字母,下劃線")
        ],
        render_kw={"class":"form-control"}
    )

    repassword = simple.PasswordField(
        label="再次輸入密碼",
        validators = [
            validators.DataRequired(message="密碼不能爲空"),
            validators.Length(min=4,max=16,message="大於4位小於16位"),
            validators.Regexp(regex="\w+",message="密碼必須爲數字,字母,下劃線"),
            validators.equal_to("password",message="兩次密碼不一致")
        ],
        render_kw={"class":"form-control"}
    )

    gender = core.RadioField(
        label="性別",
        choices=(
            (1,"男"),
            (2,"女"),
        ),
        coerce=int,  # 獲取數據時,獲取的是前面的數字
        default=1    # 默認選中值
    )
  1. 類需要繼承Form
  2. 簡單標籤用simple,複雜標籤用core
  3. validators用來校驗字符串

校驗方法

from register_forms import RegisterForm

class Register(views.MethodView):
    def get(self):
        regfm = RegisterForm()    # 實例化
        return render_template("register.html",fm=regfm)

    def post(self):
        regfm = RegisterForm(request.form)
        print(request.form)
        if not regfm.validate():  # 校驗字符串
             return render_template("register.html",fm=regfm)
        #驗證成功,則寫入數據庫
        mh = mysqlHandler()
        student_id = mh.get_student_id()+1
        student_info = [student_id,]
        for k,value in request.form.items():
            if k == "repassword":
                continue
            student_info.append(value)
        print(student_info)
        mh.write(student_info)
        return "ok"
app.add_url_rule("/register",endpoint="register",view_func=Register.as_view(name="register"))

register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊</title>
     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <h1>註冊</h1>
    <form action="" method="post">
        {% for field in fm  %}
            <div class="form-group">
                {{ field.label }} {{ field }} {{ field.errors.0 }}
            </div>
        {% endfor %}
        <button type="submit" class="btn btn-primary">登錄</button>
    </form>
</div>
</body>
</html>

{{ field.label }} 顯示label標籤
{{ field }} 顯示相應標籤
{{ field.errors.0 }} 如果有錯誤信息,顯示錯誤信息

DBUtils數據庫連接池

數據庫創建鏈接後,保持一定量的鏈接數不變,節省鏈接時間
sql_help.py

import pymysql
from DBUtils.PooledDB import PooledDB
POOL = PooledDB(
    creator=pymysql,   #使用數據庫的模塊
    maxconnections=6,  #最大連接數
    mincached=2,       # 初始化時,連接池中最少的空閒鏈接,0表示不創建
    maxcached=5,       #連接池中最多閒置的鏈接,0和None表示不限制
    maxshared=3,       #連接池中最多共享的鏈接數,0和None表示全部共享,無用因爲無論怎麼設置都爲全部共享
    blocking=True,    #連接池中如果沒有可用的鏈接後是否阻塞等待   True  or False
    maxusage=None,    #一個鏈接最多的重複使用次數,None表示無限制
    setsession=[],    #開始會話前執行的命令列表
    ping=0,
    #ping mysql服務器,檢查服務是否可用
    #0  永遠不ping     1 創建數據庫鏈接前   2創建cursor時 4 執行execute時   7任何時候
    host="127.0.0.1",
    port=3306,
    user="root",
    password='123',
    database='students_infov2',
    charset='utf8'
)

if __name__ == "__main__":
    conn = POOL.connection()  # 從連接池拿出鏈接
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    # DictCursor將查詢的東西字典化
    print("連接成功")
    res = cursor.execute("select * from student_info")
    print(cursor.fetchall())
    cursor.close()
    conn.close()  # 將連接放回連接池

websocket

websocket同時是用來做即時通訊(IM)
需要安裝gevent-websocket
輪詢:不斷向服務器發起詢問,服務器還不斷回覆,浪費前端、後端、帶寬,保證數據的實時性
長輪詢:
方法一:客戶端向服務器發起消息,服務端輪詢,有數據則放到另外一個地方,客戶端去另外一個地方去拿
方法二:服務器輪詢,放到另外一個地方,直接推給客戶端,優點,釋放客戶端資源,釋放客戶端資源,服務壓力不可避免,節省帶寬資源,數據不能實時性
方法三:客戶端和服務端開啓一個連接不斷開,有消息直接推送過去,徹底解決實時性,解決帶寬佔用問題,解決資源,客戶端和服務器都需要開啓多線程
flask默認使用werkzug處理請求(app.run())
websocket使用wsgi處理請求(經過websocket處理後,將wsgi.websocket對象加入environ,再由app處理)

羣聊

web_socket.py

from flask import Flask,request,render_template
from geventwebsocket.websocket import WebSocket
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
import json
app = Flask(__name__)


@app.route('/')
def hello_world():
    return render_template("index.html")

user_socket_list = []
@app.route("/ws/<username>")
def ws(username):  
# 獲取請求參數中的,websocket套接字
    user_socket = request.environ.get('wsgi.websocket') # type:WebSocket
    print(user_socket)
    if user_socket:
        user_socket_list.append(user_socket)
    else:
        # 沒有建立連接
        return "沒有建立連接"
    print("user_list",user_socket_list)
    while 1:
        try:
            # 如果當前用戶已經關閉,即返回None,終止連接
            msg = user_socket.receive()  # 接受用戶信息
            for socket in user_socket_list:
            # 如果發送連接失敗,則鏈接失效,在鏈接列表中刪除鏈接
                if socket != user_socket:
                    #包裝成json格式,發送
                    msg_json = json.dumps({
                        "user":username,
                        "msg":msg
                    })
                    socket.send(msg_json)  # 發送用戶信息
        except:

            user_socket_list.remove(user_socket)
            return "連接關閉"

if __name__ == '__main__':
    http_serv = WSGIServer(("127.0.0.1",5000),app,handler_class=WebSocketHandler)
    http_serv.serve_forever()
    # app.run()

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>websocket</title>
    <style>
        .send_window{
            border:2px solid black;
            width:500px;
            height:1000px;
        }
    </style>
</head>
<body>
<h1>websocket測試</h1>
<p>
    <input type="text" id="username">
    <button id="user_btn">確認姓名</button>
</p>
<p>
    <input type="text" id="send_text">
    <button id="send_btn">發送</button>
</p>

<div class="send_window">

</div>
</body>
<script type="text/javascript">
    var user_btn = document.getElementById("user_btn");
    var send_window = document.getElementsByClassName("send_window")[0];
    var username = document.getElementById("username");
    var ws = null;
    user_btn.onclick = function () {
    {#   協議頭必須爲ws://  用ws建立協議 #}
        ws = new WebSocket("ws://127.0.0.1:5000/ws/"+username.value);
        {#    前端接受json字符串{user:'alex',msg:'123'}#}
        ws.onmessage = function (data) {
            data = JSON.parse(data.data);
            send_window.innerHTML += "<p>"+ data.user + ":" + data.msg+"</p>"
        };
    };

    var send_btn = document.getElementById("send_btn");
    send_btn.onclick = function () {
        var send_text = document.getElementById("send_text");
        ws.send(send_text.value);
        send_window.innerHTML += "<p style='text-align:right'>"+  send_text.value + ":" + username.value +"</p>";
        send_text.value = "";
    }

</script>
</html>

前端
ws = new websocket(“ws連接地址”)
ws.send("") 發送消息
ws.onmessage = func 接受消息
後端
reqeust.environ.get(‘wsgi.websocket’) 獲取socket
socket.send() 發送
socket.receive 接受

單聊

web_socket.py

from flask import Flask,request,render_template
from geventwebsocket.websocket import WebSocket
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
import json
app = Flask(__name__)


@app.route('/')
def hello_world():
    return render_template("index2.html")

user_socket_list = {}
@app.route("/ws/<username>")
def ws(username):
    user_socket = request.environ.get('wsgi.websocket') # type:WebSocket
    print(user_socket)
    if user_socket:
        user_socket_list[username] = user_socket
    else:
        # 沒有建立連接
        return "沒有建立連接"
    print("user_list",user_socket_list)
    while 1:
        try:
            # 如果當前用戶已經關閉,即返回None,終止連接
            recv_data = user_socket.receive()
            recv = json.loads(recv_data)
            print(recv)
            to_sender = recv.get("to_sender")
            msg = recv.get("msg")
            to_send_sock = user_socket_list.get(to_sender)
            #包裝成json格式,發送
            msg_json = json.dumps({
                "user":username,
                "msg":msg
            })
            to_send_sock.send(msg_json)
        except:
            user_socket_list.pop(username)
            return "連接關閉"


if __name__ == '__main__':
    http_serv = WSGIServer(("127.0.0.1",5000),app,handler_class=WebSocketHandler)
    http_serv.serve_forever()
    # app.run()

index.py

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>帶暱稱的單聊</title>
    <style>
        .send_window{
            border:2px solid black;
            width:500px;
            height:1000px;
        }
    </style>
</head>
<body>
<h1>websocket測試</h1>
<p>
    <input type="text" id="username">
    <button id="user_btn">確認姓名</button>
</p>
<p>接收人<input type="text" id="to_send"></p>
<p>
    <input type="text" id="send_text">
    <button id="send_btn">發送</button>
</p>

<div class="send_window">

</div>
</body>
<script type="text/javascript">
    var user_btn = document.getElementById("user_btn");
    var send_window = document.getElementsByClassName("send_window")[0];
    var username = document.getElementById("username");
    var ws = null;
    user_btn.onclick = function () {
        ws = new WebSocket("ws://127.0.0.1:5000/ws/"+username.value);
        {#    前端接受json字符串{user:'alex',msg:'123'}#}
        ws.onmessage = function (data) {
            data = JSON.parse(data.data);
            send_window.innerHTML += "<p>"+ data.user + ":" + data.msg+"</p>"
        };
    };
    var send_btn = document.getElementById("send_btn");
    send_btn.onclick = function () {
        var to_send = document.getElementById("to_send");
        var send_text = document.getElementById("send_text");
        var to_json = {
            "to_sender":to_send.value,
            "msg":send_text.value
        };
        ws.send(JSON.stringify(to_json));
        send_window.innerHTML += "<p style='text-align:right'>"+  send_text.value + ":" + username.value +"</p>";
        send_text.value = "";
    }
</script>
</html>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章