Flask操作

[TOC]

1. flask_login实现登录功能

from flask import Flask, request, render_template, redirect, url_for
from flask_login import LoginManager, login_required, login_user, logout_user, UserMixin

# 程序实例(app)是Flask对象,参数是程序主模块的名字__name__
app = Flask(__name__)
# Login_Manager初始化与配置
login_manager = LoginManager()
login_manager.init_app(app)
# 设置密钥值,会用在表单提交等地方
app.config['SECRET_KEY'] = '234rsd12312sadfrwsf'

# 需要自定义用户模型类
class User(UserMixin):
    pass
# 注册用户
users = [
    {'id': 1, 'username': 'v_jyzang', 'password': '123'},
    {'id': 2, 'username': 'yipingdeng', 'password': '123'},
]
# 从list(或者数据库)中查询id,返回对应的用户对象
def query_user(id):
    for user in users:
        if id == str(user['id']):
            return user

# 定义回调函数,通过id返回用户对象(flask_login必须要有这个方法)
@login_manager.user_loader
def load_user(id):
    if query_user(id) is not None:
        cur_user = User()
        # 动态语言,可以动态增加新成员属性
        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方法的参数
        # request。form.get(key) 传递POST方法的参数
        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
            # 调用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. 前端分页

参考:https://www.jianshu.com/p/d45a470d2762

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>Home</title>

    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
    <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]="不确定";

        //接收后端传来的全部数据
        var result = eval('{{ result|safe }}');
        //组织表格数据
        var head = '<thead><tr>'+
            '<td>歌曲id</td>'+
            '<td>歌曲名</td>'+
            '<td>歌手名</td>'+
            '<td>候选Tip</td>'+
            '<td>点赞数</td>'+
            '<td>标签</td>'+
            '</tr></thead><tbody>';
        //表内容
        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);
        }
        //表结尾
        var end='</tbody>';

        $(function(){
            var Count = pageData.length; //记录条数
            var PageSize = 10; //设置每页示数目
            var PageCount = Math.ceil(Count/PageSize); //计算总页数
            var currentPage = 1; //当前页,默认为1。

            //分页按钮
            for(var i = 1; i <= PageCount; i++){
                var pageN='<a href="#" selectPage="'+i+'" >   '+i+'   </a>';
                $('#page').append(pageN);
            }

            //清空table,默认填充第一页内容
            $('#table').empty().append(head);
            for(i = (currentPage-1)*PageSize; i < PageSize*currentPage; i++){
                $('#table').append(pageData[i]);
            }
            $('#table').append(end);

            //显示选择页的内容
            $('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;">页数</div>
        </div>
    </div>
</body>
</html>
image.png

3. ajax异步提交,当前页面响应

javascript

<script>
        function add_ajax(i) {
            $.ajax({
                url: '/mark',
                type: 'GET',
                data: $('#mark'+i).serialize(), //序列化为键值对
                success: function (data) { // 返回2XX响应后触发的回调函数
                    $('#mark'+i).append(data); // 将返回的响应插入到页面中
                },
                error: function (data) {
                    $('#mark'+i).append("Error");
                }
            });
            //响应信息在当前页面插入,而不是另起页面显示
            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="标记">
        </form>
    {% endfor %}
</html>
image.png

jquery其他事件绑定:

eg. 
//放在回调函数里,防止页面还没有加载好的时候就运行jquery
$(function(){
    $('form').submit(function(){...});
});
blur() 元素失去焦点
focus() 元素获得焦点
click() 鼠标单击
mouseover() 鼠标进入(进入子元素也触发)
mouseout() 鼠标离开(离开子元素也触发)
mouseenter() 鼠标进入(进入子元素不触发)
mouseleave() 鼠标离开(离开子元素不触发)
hover() 同时为mouseenter和mouseleave事件指定处理函数
ready() DOM加载完成
resize() 浏览器窗口的大小发生改变
scroll() 滚动条的位置发生变化
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  # 总数据
        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  # 总页数
        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):
        """
        获取一页的数据
        :param page: 要返回数据的页码
        :return: 如果页码超过总页码,返回空列表,否则返回一页的数据
        """
        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回调函数中清除table信息,重新填充下一页信息。
缺点:刷新之后会返回第一页,不会留在当前页;如果在某一页点击详情进入新页面,回退之后也只会回到第一页

<button type="button" class = "pagebtn" onclick="next_page(-1)">上一页</button>
<span id ="page_display" style="display: inline">当前页1/{{page_num}}</span>
<button type="button" class = "pagebtn" onclick="next_page(1)">下一页</button>
<script>
    cur_page = 1; // 当前页面号会随页面变化而变化
    传值都是string要转Int!!!
    table_length = parseInt("{{ page_num }}"); //js中引用jinja2的变量要用双引号括起来
    //翻页函数
    // 参数:当前页号,总页数,向前/后一页
    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){
            //创建表单
            var formData = new FormData();
            formData.append("cur_page", cur_page);
            //ajax提交表单
            $.ajax({
                url: '/page',
                type: 'POST', //用GET不行,不明
                data: formData,
                success: function (data) { // 返回2XX响应后触发的回调函数
                    $('#table').empty();
                    // 将json数据转为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('当前页' + 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"))
    ....查询全部结果
    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">当前页{{ 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的变量要用双引号括起来
    //翻页函数
    // 参数:当前页号,总页数,向前/后一页
    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创建表单
            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()函数,不用新增page()函数
@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
    ····查询全部结果
    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)

image.png

要做出详细页码参考:https://www.cnblogs.com/w-yong/p/6255444.html

5. Bootstrap进度条

https://www.cnblogs.com/accordion/p/7764460.html
后端运行模型,运行结束后页面跳转,运行期间用进度条撑着

// EventSource实时通信,服务端向客户端推送信息,客户端无需发送请求
    <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>
// 点击事件发生,显示进度条,提交表单
<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函数传递信号,通过全局变量progress_percentage反馈给前端
from flask import Response
@app.route('/progress')
def progress():
    def generate():
        global progress_percentage
        //两个换行符表示当前消息发送完毕
        return "data:" + str(progress_percentage) + "\n\n"
    //事件流对应的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
    ....
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容