[TOC]
1. flask_login實現(xiàn)登錄功能
from flask import Flask, request, render_template, redirect, url_for
from flask_login import LoginManager, login_required, login_user, logout_user, UserMixin
# 程序?qū)嵗?app)是Flask對象域携,參數(shù)是程序主模塊的名字__name__
app = Flask(__name__)
# Login_Manager初始化與配置
login_manager = LoginManager()
login_manager.init_app(app)
# 設(shè)置密鑰值看锉,會用在表單提交等地方
app.config['SECRET_KEY'] = '234rsd12312sadfrwsf'
# 需要自定義用戶模型類
class User(UserMixin):
pass
# 注冊用戶
users = [
{'id': 1, 'username': 'v_jyzang', 'password': '123'},
{'id': 2, 'username': 'yipingdeng', 'password': '123'},
]
# 從list(或者數(shù)據(jù)庫)中查詢id,返回對應(yīng)的用戶對象
def query_user(id):
for user in users:
if id == str(user['id']):
return user
# 定義回調(diào)函數(shù)疼电,通過id返回用戶對象(flask_login必須要有這個方法)
@login_manager.user_loader
def load_user(id):
if query_user(id) is not None:
cur_user = User()
# 動態(tài)語言界弧,可以動態(tài)增加新成員屬性
cur_user.id = id
return cur_user
@app.route('/tip')
@login_required
def tip():
return render_template("index.html")
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# request.args.get(key) 傳遞GET方法的參數(shù)
# request凿跳。form.get(key) 傳遞POST方法的參數(shù)
id = request.form.get('username')
user = query_user(id)
if user is not None and request.form['password']==user['password']:
cur_user = User()
cur_user.id = id
# 調(diào)用login_user()方法良拼,傳入用戶對象
login_user(cur_user)
return redirect(url_for('tip'))
return render_template("login.html")
@app.route('/logout')
@login_required
def logout():
logout_user()
if __name__ == '__main__':
app.run()
2. 前端分頁
參考:http://www.reibang.com/p/d45a470d2762
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Home</title>
<link rel="stylesheet" >
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
{#<link rel="stylesheet" href="../static/assets/css/style.css">#}
<script type="text/javascript">
var nums=new Array(10);
nums[0]="不是";
nums[1]="是";
nums[2]="不確定";
//接收后端傳來的全部數(shù)據(jù)
var result = eval('{{ result|safe }}');
//組織表格數(shù)據(jù)
var head = '<thead><tr>'+
'<td>歌曲id</td>'+
'<td>歌曲名</td>'+
'<td>歌手名</td>'+
'<td>候選Tip</td>'+
'<td>點贊數(shù)</td>'+
'<td>標(biāo)簽</td>'+
'</tr></thead><tbody>';
//表內(nèi)容
var pageData=[];
for(var i = 0; i < result.length; i++){
var data = '<tr>'+
'<td>'+result[i][1]+'</td>'+
'<td>'+result[i][5]+'</td>'+
'<td>'+result[i][6]+'</td>'+
'<td>'+result[i][2]+'</td>'+
'<td>'+result[i][3]+'</td>'+
'<td>'+nums[result[i][4]]+'</td>'+
'<td>'+
'<form action="/select_tip" method="get">'+
'<input type="hidden" name="id" value="'+result[i][0]+'" >'+
'<input type="submit" name="tag" class="btn btn-sm btn-default" value="查看">'+
'</form>'+
'</td>'+
'</tr>';
pageData.push(data);
}
//表結(jié)尾
var end='</tbody>';
$(function(){
var Count = pageData.length; //記錄條數(shù)
var PageSize = 10; //設(shè)置每頁示數(shù)目
var PageCount = Math.ceil(Count/PageSize); //計算總頁數(shù)
var currentPage = 1; //當(dāng)前頁,默認(rèn)為1就斤。
//分頁按鈕
for(var i = 1; i <= PageCount; i++){
var pageN='<a href="#" selectPage="'+i+'" > '+i+' </a>';
$('#page').append(pageN);
}
//清空table悍募,默認(rèn)填充第一頁內(nèi)容
$('#table').empty().append(head);
for(i = (currentPage-1)*PageSize; i < PageSize*currentPage; i++){
$('#table').append(pageData[i]);
}
$('#table').append(end);
//顯示選擇頁的內(nèi)容
$('a').click(function(){
var selectPage = $(this).attr('selectPage');
$('#no_page').html(selectPage);
//清空table,重新填充
$('#table').html('');
$('#table').append(head);
for(i = (selectPage-1)*PageSize; i < PageSize*selectPage; i++){
$('#table').append(pageData[i]);
}
$('#table').append(end);
});
});
</script>
</head>
<body>
<div class="wrapper">
<div class="form-top1"> <!--底框-->
<h3 class="text-center">Home</h3>
<table class="table table-bordered" id="table" border="1">
</table>
<span id="no_page"></span>
<div id="page" style="width:450px;margin:0 auto;">頁數(shù)</div>
</div>
</div>
</body>
</html>
3. ajax異步提交洋机,當(dāng)前頁面響應(yīng)
javascript
<script>
function add_ajax(i) {
$.ajax({
url: '/mark',
type: 'GET',
data: $('#mark'+i).serialize(), //序列化為鍵值對
success: function (data) { // 返回2XX響應(yīng)后觸發(fā)的回調(diào)函數(shù)
$('#mark'+i).append(data); // 將返回的響應(yīng)插入到頁面中
},
error: function (data) {
$('#mark'+i).append("Error");
}
});
//響應(yīng)信息在當(dāng)前頁面插入坠宴,而不是另起頁面顯示
return false;
}
</script>
html
<html>
//傳給后端做處理,后端傳遞返回值給success字段
{% for i in range(3) %}
<form id="mark{{ i }}" onsubmit="return add_ajax({{ i }})">
<input type="hidden" name="mark_id" value="sbasa">
<input type="submit" id="biaoji{{ i }}" value="標(biāo)記">
</form>
{% endfor %}
</html>
jquery其他事件綁定:
eg.
//放在回調(diào)函數(shù)里绷旗,防止頁面還沒有加載好的時候就運行jquery
$(function(){
$('form').submit(function(){...});
});
blur() 元素失去焦點
focus() 元素獲得焦點
click() 鼠標(biāo)單擊
mouseover() 鼠標(biāo)進入(進入子元素也觸發(fā))
mouseout() 鼠標(biāo)離開(離開子元素也觸發(fā))
mouseenter() 鼠標(biāo)進入(進入子元素不觸發(fā))
mouseleave() 鼠標(biāo)離開(離開子元素不觸發(fā))
hover() 同時為mouseenter和mouseleave事件指定處理函數(shù)
ready() DOM加載完成
resize() 瀏覽器窗口的大小發(fā)生改變
scroll() 滾動條的位置發(fā)生變化
submit() 用戶遞交表單
4. 后端分頁
參考:https://www.cnblogs.com/wuxie1989/p/7027843.html
http://www.manongjc.com/detail/13-kxskdzykqjfjnws.html
#定義Pager類
class Pager:
def __init__(self, data, page_size):
self.data = data # 總數(shù)據(jù)
self.page_size = page_size # 單頁大小
self.is_start = False
self.is_end = False
self.data_count = len(data)
self.next_page = 0 # 下一頁
self.previous_page = 0 # 上一頁
self.page_num = self.data_count / page_size # 總頁數(shù)
if self.page_num == int(self.page_num):
self.page_num = int(self.page_num)
else:
self.page_num = int(self.page_num) + 1
def page_data(self, page):
"""
獲取一頁的數(shù)據(jù)
:param page: 要返回數(shù)據(jù)的頁碼
:return: 如果頁碼超過總頁碼喜鼓,返回空列表,否則返回一頁的數(shù)據(jù)
"""
print(page, self.page_num)
if page > self.page_num:
return []
self.next_page = page + 1
self.previous_page = page - 1
if page == 1:
self.is_start = True
elif page == self.page_num:
self.is_end = True
if self.is_end:
return self.data[(page - 1) * self.page_size:]
else:
return self.data[(page - 1) * self.page_size:page * self.page_size]
法一:在不刷新頁面的前提下翻頁衔肢,利用ajax提交翻頁請求(瀏覽器url不變庄岖,不顯示page),success回調(diào)函數(shù)中清除table信息角骤,重新填充下一頁信息隅忿。
缺點:刷新之后會返回第一頁,不會留在當(dāng)前頁邦尊;如果在某一頁點擊詳情進入新頁面背桐,回退之后也只會回到第一頁
<button type="button" class = "pagebtn" onclick="next_page(-1)">上一頁</button>
<span id ="page_display" style="display: inline">當(dāng)前頁1/{{page_num}}</span>
<button type="button" class = "pagebtn" onclick="next_page(1)">下一頁</button>
<script>
cur_page = 1; // 當(dāng)前頁面號會隨頁面變化而變化
傳值都是string要轉(zhuǎn)Int!2踝帷链峭!
table_length = parseInt("{{ page_num }}"); //js中引用jinja2的變量要用雙引號括起來
//翻頁函數(shù)
// 參數(shù):當(dāng)前頁號,總頁數(shù)又沾,向前/后一頁
function next_page(offset){
cur_page = cur_page + offset; //翻頁
//越界
if (cur_page < 1){
cur_page = 1;
}
else if (cur_page > table_length){
cur_page = table_length;
}
if(cur_page <= table_length && cur_page >= 1){
//創(chuàng)建表單
var formData = new FormData();
formData.append("cur_page", cur_page);
//ajax提交表單
$.ajax({
url: '/page',
type: 'POST', //用GET不行弊仪,不明
data: formData,
success: function (data) { // 返回2XX響應(yīng)后觸發(fā)的回調(diào)函數(shù)
$('#table').empty();
// 將json數(shù)據(jù)轉(zhuǎn)為JavaScript對象
var dict_data = $.parseJSON(data);
var pageData=[];
for(var i = 1; i < dict_data.page_data.length; i++) {
var data = '<tr>' +
'<td>' + dict_data.page_data[i][1] + '</td>' +
'<td>' + dict_data.page_data[i][5] + '</td>' +
'<td>' + dict_data.page_data[i][6] + '</td>' +
'<td>' + dict_data.page_data[i][2] + '</td>' +
'<td>' + dict_data.page_data[i][3] + '</td>' +
'<td>' + dict_data.page_data[i][4] + '</td></tr>';
pageData.push(data)
}
$('#table').append(pageData)
$('#page_display').html('當(dāng)前頁' + dict_data.cur_page + '/' + dict_data.page_num)
},
error: function (data) {},
//傳遞FormData時需要這兩行
processData: false,
contentType: false
});
}
}
</script>
@app.route('/page', methods=["GET", "POST"])
@login_required
def page():
cur_page = int(request.form.get("cur_page"))
....查詢?nèi)拷Y(jié)果
pager = Pager(result, page_size=10)
return json.dumps({"page_data": pager.page_data(cur_page),
"page_num": pager.page_num,
"cur_page": cur_page})
法二:改進法一的缺點,讓瀏覽器url記錄頁碼信息(好像也可以用cookie做)這樣回退或刷新不會永遠在第一頁
<button type="button" class = "pagebtn" onclick="next_page(-1)">上一頁</button>
<span id ="page_display" style="display: inline">當(dāng)前頁{{ cur_page }}/{{ page_num }}</span>
<button type="button" class = "pagebtn" onclick="next_page(1)">下一頁</button>
<script>
cur_page = parseInt("{{ cur_page }}");
page_num = parseInt("{{ page_num }}"); //js中引用jinja2的變量要用雙引號括起來
//翻頁函數(shù)
// 參數(shù):當(dāng)前頁號捍掺,總頁數(shù)撼短,向前/后一頁
function next_page(offset){
cur_page = cur_page + offset; //翻頁
//越界
if (cur_page < 1){
cur_page = 1;
}
else if (cur_page > page_num){
cur_page = page_num;
}
console.log(cur_page);
if(cur_page <= page_num && cur_page >= 1){
// jquery創(chuàng)建表單
var form = $('<form></form>')
form.attr('action', '/panel');
form.attr('method', 'get');
var my_input = $('<input type="hidden" name="cur_page" />');
my_input.attr('value', cur_page);
form.append(my_input);
$("body").append(form);
form.submit(); //此法提交,瀏覽器url會記錄
}
}
</script>
后端直接使用原panel()函數(shù)挺勿,不用新增page()函數(shù)
@app.route('/panel', methods=["GET", "POST"])
@login_required
def panel():
cur_page = request.args.get('cur_page')
cur_page = int(cur_page) if cur_page else 1
····查詢?nèi)拷Y(jié)果
pager = Pager(result, page_size=PAGE_SIZE)
return render_template('panel.html',
username=current_user.username,
page_data = pager.page_data(cur_page),
page_num = pager.page_num,
cur_page = cur_page)
要做出詳細頁碼參考:https://www.cnblogs.com/w-yong/p/6255444.html
5. Bootstrap進度條
https://www.cnblogs.com/accordion/p/7764460.html
后端運行模型,運行結(jié)束后頁面跳轉(zhuǎn)喂柒,運行期間用進度條撐著
// EventSource實時通信不瓶,服務(wù)端向客戶端推送信息禾嫉,客戶端無需發(fā)送請求
<script>
var source = new EventSource("/progress");
source.onmessage = function (event) {
$('.progress-bar').css('width', event.data + '%').attr('aria-valuenow', event.data);
$('.progress-bar-label').text(event.data + '%');
if (event.data === '100') { // 到100斷開連接
source.close()
}
}
function showbar() {
$('.progress').css('display', 'block');
}
</script>
// 點擊事件發(fā)生,顯示進度條蚊丐,提交表單
<form ...action='/panel'>
<button type="button" class = "pagebtn" onclick="showbar()">下一頁</button>
</form ...>
// 進度條模塊熙参,需引入bootstrap
<div class="progress" style="margin: 50px; display: none">
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100" style="width: 0%">
<span class="progress-bar-label">0%</span>
</div>
</div>
// progress函數(shù)傳遞信號,通過全局變量progress_percentage反饋給前端
from flask import Response
@app.route('/progress')
def progress():
def generate():
global progress_percentage
//兩個換行符表示當(dāng)前消息發(fā)送完畢
return "data:" + str(progress_percentage) + "\n\n"
//事件流對應(yīng)的MIME格式
return Response(generate(), mimetype='text/event-stream')
//全局變量progress_percentage控制進度
progress_percentage=0
def panel():
...
global progress_percentage
time.sleep(5) // model1
progress_percentage += 50
time.sleep(5) //model2
progress_percentage += 50
....