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 # 默認選中值
)
- 類需要繼承Form
- 簡單標籤用simple,複雜標籤用core
- 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>