Python进阶Flask入门

Flask简介

架构简介

  • Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。
    nginx的作用:

    • 1.反向代理,可以拦截一些web攻击,保护后端的web服务器
    • 2.负载均衡,根据轮询算法,分配请求到多节点web服务器
    • 3.缓存静态资源,加快访问速度,释放web服务器的内存占用,专项专用
      首先说明一下,如果不用nginx一样可以访问web项目,使用nginx的目的是为了安全和负载均衡。配置了nginx做前端代理,uwsgi作后端代理的服务器(这里所说的前后端都是相对的位置,并无实际含义),在处理来自Internet的请求时,要先经过nginx的处理,nginx把请求再交给uwsgi,经过uwsgi才能访问到项目本身。
      没有nginx而只有uwsgi的服务器,则是Internet请求直接由uwsgi处理,并反馈到web项目中。nginx可以实现安全过滤,防DDOS等保护安全的操作,并且如果配置了多台服务器,nginx可以保证服务器的负载相对均衡。
      而uwsgi则是一个web服务器,实现了WSGI协议(Web Server Gateway Interface),http协议等,它可以接收和处理请求,发出响应等。所以只用uwsgi也是可以的。
  • uWSGI是一个全功能的HTTP服务器,实现了WSGI协议、uwsgi协议、http协议等。它要做的就是把HTTP协议转化成语言支持的网络协议。比如把HTTP协议转化成WSGI协议,让Python可以直接使用。
    其中:

    • WSGI的全称是Web Server Gateway Interface(Web服务器网关接口),它不是服务器、python模块、框架、API或者任何软件,只是一种描述web服务器(如nginx,uWSGI等服务器)如何与web应用程序(如用Django、Flask框架写的程序)通信的规范、协议。
      server和application的规范在PEP3333中有具体描述,要实现WSGI协议,必须同时实现web server和web application,当前运行在WSGI协议之上的web框架有,Flask, Django。
    • uwsgi
      与WSGI一样,是uWSGI服务器的独占通信协议,用于定义传输信息的类型。每一个uwsgi packet前4byte为传输信息类型的描述,与WSGI协议是两种东西,据说该协议是fcgi协议的10倍快。
      uWSGI的适用:
    • 1.单节点服务器的简易部署
    • 2.轻量级,好部署
  • Framework即架构,它是一个语言开发软件,提供了软件开发的框架,使开发更具工程性、简便性和稳定性。

在这里插入图片描述

什么是Flask?

Flask是一个Web框架,就是提供一个工具库和技术来允许你构建一个Web应用程序.这个Web应用程序可以是一些Web页面,博客, wiki ,基于 Web 的日历应用或商业网站。
Flask依赖模块:

  • web服务网关接口(Python Web Server Gateway Interface,缩写为WSGI
  • Werkzeug 一个WSGI工具包, 是为python语言定义的web服务器和web应用程序或框架之间的一种简单而通用的借口,其他语言也有类似的接口)
  • jinja2模板引擎

Flask的优势

Flask属于微框架( micro-framework )这一类别,微架构通常是很小的不依赖外部库的框架.

  • 框架很轻量
  • 更新时依赖小
  • 专注于安全方面的bug

Flask第一个网站

具体步骤:
1、从flask模块中导入Flask
2、实例化出来一个Flask对象app,必须传入当前的模块名
3、配置路由@app.route(),url访问的路径
4、编写视图函数,给用户返回信息
5、运行Flask对象app.run()

from flask import Flask

app = Flask(__name__)
print(__name__)
# 实现首页:http://172.25.254.15:9999/ 如何确保返回的东西?就要使用到路由
@app.route('/') # 路由  /代表提交的路径是‘/’
def index(): # 试图函数
    return '这是网站首页'
@app.route('/login')
def login():
    return '正在登陆。。。'
@app.route('/logout')
def logout():
    return '正在退出'
if __name__ == '__main__':
    # 运行Flask项目,默认ip和端口号127.0.0.1:5000
    # 如何特色化指定?host = ‘0.0.0.0’ 开放本地所有ip port=5000 端口必须是整数
    # debug=True开启调试模式。测试环境中开启,生产环境一定要关闭
    app.run(host='0.0.0.0',port=9999,debug=True)

可以在浏览器中搜索127.0.0.1:9999+路由,来查看实验结果

动态路由

# 动态路由
import json
from flask import Flask,request  # request请求头部,服务端用来获取客户端请求的信息
app = Flask(__name__)
@app.route('/<int:userid>/')
def userinfo(userid):
    return '正在查看用户%d的博客详情' %(userid)
@app.route('/welcome/<string:username>')
def welcome(username):
    return '欢迎访问%s用户的主页' %(username)
@app.route('/top250')
# url为127.0.0.1/top250?start=10  通过?start来设置参数
def top250():
    users = ['user%s' %(i) for i in range(100)]
    print('客户端的用户代理', request.user_agent)
    print('请求页面的头部信息',request.headers)
    print('客户端的ip:',request.remote_addr)
    print('客户端请求的参数详细信息:',request.args) #ImmutableMultiDict([('start', '25'), ('user', 'westos')])
    # 获取用户请求的url地址里面key对应的value值,通过get方法
    start = int(request.args.get('start'))
    user = request.args.get('user')
    print('客户端HTTP请求的方法',request.method)
    return json.dump(users[start:])
if __name__ == '__main__':
    app.run(host='0.0.0.0',port=9998,debug=True)

客户端的用户代理 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36
请求页面的头部信息 Host: 127.0.0.1:9998
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8
客户端的ip: 127.0.0.1
客户端请求的参数详细信息: ImmutableMultiDict([(‘start’, ‘10’), (‘user’, ‘westos’)])
客户端HTTP请求的方法 GET
westos

案例:登陆验证get和post方法
get方法:

from flask import Flask, render_template, request, redirect
app = Flask(__name__)
@app.route('/')
def index():
    return '<h1>主页</h1>'
@app.route('/login/')
def login():
    """
    一般情况下,不会把html代码直接返回
    而是将html文件保存到当前的template目录中
        1)通过render_template方法调用
        2)默认情况下,Flask在程序文件夹中的templates(目前最好是这个)子文件中寻找模版
    :return:
    """
    return render_template('login.html')
@app.route('/login2/')
def login2():
    # 获取用户输入的用户名
    username = request.args.get('username',None)
    password = request.args.get('password',None)
    # 逻辑处理,判断用户名和密码是否正确
    if username == 'root' and password == 'redhat':
        # 重定向到指定路由
        return redirect('/')
    else:
        return redirect('/login/')

if __name__ == '__main__':
    app.run()

post方法:
注:在浏览器中第一次输入url请求页面时,使用的是get方法,当在表单中填入信息点击提交后,使用的是form中指定的方式进行提交

from flask import Flask, render_template, request, redirect, abort

app = Flask(__name__)
@app.route('/')
def index():
    return '<h1>主页</h1>'
# 默认路由只支持客户端http请求的get方法, methods=['GET','POST']表示可以接收的客户端http请求方法有'GET','POST'
@app.route('/login/',methods=['GET','POST'])
def login():
    if request.method == 'POST':
        # 难点:post请求提交的数据如何获取?request.form
        # 难点:get请求提交的数据如何获取?request.args
        print(request.form)
        username = request.form.get('username')
        password = request.form.get('password')
        if username == 'root' and password == 'redhat':
            return redirect('/')
        else:
            # 如果登陆不正确,则警告红色信息,还是在登陆页面
            # 可以给html传递变量
            return render_template('login_post.html',errMessges='用户名或密码错误')
    else:
        # abort(500) # 抛出500的错误就会执行@app.errorhandler(500)
        return render_template('login_post.html')
# 网页中的几种错误:404网页找不到,500服务器错误
@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html')
@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html')

if __name__ == '__main__':
    app.run()

总结:http的请求方法
HTTP/1.1协议中共定义了八种方法(有时也叫“动作”),来表明Request-URL指定的资源不同的操作方式
HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法

在这里插入图片描述
目前常用的是get和post方法
两者的区别为;
1). url可见性:
get,参数url可见;
post,url参数不可见
2). 数据传输上:
get,通过拼接url进行传递参数;
post,通过body体传输参数
3). 缓存性:
get请求是可以缓存的
post请求不可以缓存
4). 后退页面的反应
get请求页面后退时,不产生影响
post请求页面后退时,会重新提交请求
5). 传输数据的大小
get一般传输数据大小不超过2k-4k(根据浏览器不同,限制不一样,但相差不大)
post请求传输数据可以无限大。
6). 安全性: 原则上post肯定要比get安全。

Flask日志记录

from flask import Flask
import logging
app = Flask(__name__)
# 日志系统配置,设置文件存放的位置
handler = logging.FileHandler('flask.log',encoding='UTF-8')
# 设置日志文件存储格式
logging_format = logging.Formatter(
    '%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s')
# 将日志文件处理对象和日志格式绑定
handler.setFormatter(logging_format)
# 设置日志的等级
handler.setLevel(logging.INFO)
# 将日志格式和app绑定
app.logger.addHandler(handler)

@app.route('/')
def index():
    app.logger.debug('hello')
    app.logger.error('error')
    app.logger.exception('exception')
    app.logger.info('info')
    return 'index'

if __name__ == '__main__':
    app.debug=True
    app.run()

在这里插入图片描述
日志格式化的参数:

%(name)sLogger的名字
%(levelno)s数字形式的日志级别
%(levelname)s文本形式的日志级别
%(pathname)s调用日志输出函数的模块的完整路径名,可能没有
%(filename)s调用日志输出函数的模块的文件名
%(module)s调用日志输出函数的模块名
%(funcName)s调用日志输出函数的函数名
%(lineno)d调用日志输出函数的语句所在的代码行
%(created)f当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d线程ID。可能没有
%(threadName)s线程名。可能没有
%(process)d进程ID。可能没有
%(message)s用户输出的消息

项目案例:基于Flask的个人博客登陆注册注销系统
首先新建一个Flask工程
在这里插入图片描述
static:静态文件,存储比如css文件、js文件、图片等
templates:模版,用来存储html文件
app.py:主程序
1、首先需要设计主页index.html、login.html、register.html
index界面如图

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>weibo</title>
    {#    <link rel="stylesheet" href="../static/css/bootstrap.css">#}
    <link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.css') }}">
    <link rel="stylesheet" href="../static/css/weibo.css">
    <script src="../static/js/jquery-3.1.0.js"></script>
    <script src="../static/js/bootstrap.min.js"></script>
    <script src="../static/js/weibo.js"></script>
</head>
<body>
<!--
一个典型导航条的结构如下:
    nav.navbar.navbar-default
        .container
            .nav-header
                a.nav-brand
nav:
    .navbar-fixed-top:固定在顶部
    .navbar-fixed-bottom:固定在底部
    . navbar-static-top: 不是固定在页面顶部的,会随页面下拉消失。
container:用于支持响应式布局的容器
    .container: fixed-with
    .container-fluid: full-width
-->
<nav class="navbar navbar-fixed-top" style="background: #e0620d ;padding-top: 3px;height:50px; ">
    <div class="container-fluid" style="background: #fff;">
        <div class="navbar-header">
            <span class="navbar-brand" href="#"> WEIBO</span>
            <button type="button" class="navbar-toggle" data-toggle="collaspe" data-target="#my-navbar-collapse">
                <span class="sr-only">切换导航</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>

            </button>
        </div>
        <form class="navbar-form navbar-left" role="search">
            <div class="form-group">
                <input type="text" class="form-control" placeholder="#热门话题#">
                <span class="glyphicon glyphicon-search btn_search"></span>
                <!--<button type="submit" class="btn btn-default">提交</button>-->
            </div>

        </form>

        <div class="collapse navbar-collapse" id="my-navbar-collapse">

            <ul class="nav navbar-nav navbar-right">
                <li><a href="#"><i class="glyphicon glyphicon-user"></i>&nbsp;&nbsp;{{ session.username }}</a></li>

                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                        设置 <b class="caret"></b>
                    </a>
                    <ul class="dropdown-menu">

                        {#
                                1. 如何让判断用户是否登录?
                                session是否存在用户信息===session.get('username')

                                如果用户登录, 则显示注销;
                                如果用户没有登录, 则显示登录和注册;


                            #}
                        {% if session.get('username') %}
                            <li><a href="/logout/">注销</a></li>

                        {% else %}
                            <li><a href="/login/">登录</a></li>
                            <li><a href="/register/">注册</a></li>

                        {% endif %}


                    </ul>
                </li>
            </ul>
        </div>
    </div>
    <hr style="margin: 0;padding: 0;color:#222;width: 100%">
</nav>
<!--
content:
    1.
    2.
-->
<p style="color: red;">{{ get_flashed_messages() }}</p>
<div class="container container-bg">
    <div class="row">
        <div class="col-sm-2"></div>
        <div class="col-sm-6 col-xs-12 my_edit">
            <div class="row" id="edit_form">
                <span class="pull-left" style="margin: 15px">编写新鲜事 </span>
                <span class="tips pull-right" style="margin:15px;"></span>
                <form role="form" style="margin-top: 50px;">
                    <!--message-->
                    <div class="col-sm-12">
                        <div contentEditable="true" id="content" class="form-control"></div>
                    </div>
                    <!--other: image and emjo-->
                    <div class="col-sm-12" style="margin-top: 12px;">
                        <span class="emoji">表情</span>
                        <span class="pic" class="imgP
                        ath">图片</span>

                        <span>
                        <input type="file" name="" class="select_Img" style="display: none">
                            <!--<img class="preview" src="">-->
                        </span>


                        <div class="myEmoji">
                            <ul id="myTab" class="nav nav-tabs">
                                <li class="active">
                                    <a href="#set" data-toggle="tab">
                                        预设
                                    </a>
                                </li>
                                <li><a href="#hot" data-toggle="tab">热门</a></li>
                            </ul>
                            <div id="myTabContent" class="tab-content">
                                <div class="tab-pane fade in active" id="set">
                                    <div class="emoji_1"></div>

                                </div>
                                <div class="tab-pane fade" id="hot">
                                    <div class="emoji_2"></div>
                                </div>

                            </div>
                        </div>


                        <button type="button" id="send" class="btn btn-default pull-right disabled">发布</button>

                    </div>
                </form>

            </div>


            <!-- message list-->
            <div class="row item_msg">
                <div class="col-sm-12 col-xs-12 message">
                    <img src="../static/img/icon.jpg" class="col-sm-2 col-xs-2" style="border-radius: 50%">
                    <div class="col-sm-10 col-xs-10">
                        {#   获取缓存中的用户名信息, session, request, g, get_flashed_messages()可以直接从前台获取后台信息                        #}
                        <span style="font-weight: bold;">{{ session.username }}</span>
                        <br>
                        <small class="date" style="color:#999">1分钟前</small>
                        <div class="msg_content">happy day!
                            <img class="mypic" src="../static/img/bg_1.jpg">
                        </div>

                    </div>

                </div>


            </div>
        </div>


        <!--right content-->

        <div class="col-sm-3 col-xs-12 part_right">
            <div class="row text-center inform">
                <img src="../static/img/icon.jpg">
                <h4 style="font-weight: bold;">{{ session.username }}</h4>
                <div class="col-sm-12 my_inform">
                    <div class="col-sm-4 col-xs-4">
                        <div>111</div>
                        <div class="sort">关注</div>

                    </div>
                    <div class="col-sm-4 col-xs-4">
                        <div>111</div>
                        <div class="sort">粉丝</div>
                    </div>
                    <div class="col-sm-4 col-xs-4">
                        <div>111</div>
                        <div class="sort">博客</div>
                    </div>
                </div>
            </div>
            <div class="row part_hot">
                <div class="col-sm-12">
                    <span class="pull-left" style="padding: 10px;font-size:16px;font-weight: bold;">热门话题</span>
                    <span class="pull-right" style="padding: 10px;">换话题</span>

                </div>


                <div class="col-sm-12 item_hot">
                    <span class="pull-left">#英雄联盟s7#</span>
                    <span class="pull-right item_num">34.6亿</span>
                </div>

                <div class="col-sm-12 item_hot">
                    <span class="pull-left">#今天霜降#</span>
                    <span class="pull-right item_num">2.6亿</span>
                </div>

                <div class="col-sm-12 item_hot">
                    <span class="pull-left">#亚洲新歌榜#</span>
                    <span class="pull-right item_num">10.4亿</span>
                </div>

                <div class="col-sm-12 item_hot">
                    <span class="pull-left">#扑通扑通少女心#</span>
                    <span class="pull-right item_num">1.5亿</span>
                </div>

                <div class="col-sm-12 item_hot">
                    <span class="pull-left">#突然开心#</span>
                    <span class="pull-right item_num">1.1亿</span>
                </div>
                <hr style="margin: 0;padding: 0;width: 100%">

                <div class="col-sm-12 text-center" style="padding: 10px"><a href="#">查看更多</a></div>

            </div>

        </div>

    </div>


</div>
<script type="text/javascript">
    $(function () {

        //*************************1. content set ************************************
        $('#content').keyup(function () {
            var content_len = $('#content').text().replace(/\s/g, "").length;
            $('.tips').text("已经输入" + content_len + "个字");

            if (content_len === 0) {
                $('.tips').text("");
                $('#send').addClass('disabled');
                return false;
            } else {
                $('#send').removeClass('disabled');
            }

        });

        //*****************************************2. pic set *************************************
        $(".pic").click(function () {
            $(".select_Img").click();


        });


        //*****************************************3. send set ****************************************

        $("#send").click(function () {
            //判断选择的是否是图片格式
            var imgPath = $(".select_Img").val();
            var start = imgPath.lastIndexOf(".");
            var postfix = imgPath.substring(start, imgPath.length).toUpperCase();
            var content = $('#content').html();
            if (imgPath != "") {

                if (postfix != ".jpg" && postfix != ".JPG" && postfix != ".GIF" && postfix != ".JPEG") {
                    alert("图片格式需为jpg,gif,jpeg,jpg格式");
                } else {
                    var uploadImg = "<img class='mypic'  src='../img/" + imgPath + '>';
                    $(".item_msg").append("<div class='col-sm-12 col-xs-12 message' > <img src='img/icon.jpg' class='col-sm-2 col-xs-2' style='border-radius: 50%'><div class='col-sm-10 col-xs-10'><span style='font-weight: bold;''>Westos</span> <br><small class='date' style='color:#999'>刚刚</small><div class='msg_content'>" + content + "<img class='mypic' οnerrοr='this.src='img/bg_1.jpg' src='img/" + imgPath + "' ></div></div></div>");

                }
            } else {
                $(".item_msg").append("<div class='col-sm-12 col-xs-12 message' > <img src='img/icon.jpg' class='col-sm-2 col-xs-2' style='border-radius: 50%'><div class='col-sm-10 col-xs-10'><span style='font-weight: bold;''>Westos</span> <br><small class='date' style='color:#999'>刚刚</small><div class='msg_content'>" + content + "</div></div></div>");
            }

        });

        //添加表情包1
        for (var i = 1; i < 60; i++) {
            $(".emoji_1").append("<img src='img/f" + i + ".jpg' style='width:35px;height:35px' >");
        }
        //添加表情包2
        for (var i = 1; i < 61; i++) {
            $(".emoji_2").append("<img src='img/h" + i + ".jpg' style='width:35px;height:35px' >");
        }

        $(".emoji").click(function () {

            $(".myEmoji").show();

            //点击空白处隐藏弹出层
            $(document).click(function (event) {
                //is 判断点击位置是否在目标区域内,如果不在,则返回false;否则true
                //has 用来判断点击的位置是否在目标区域的子元素上
                if (!$("#edit_form").is(event.target) && $("#edit_form").has(event.target).length === 0) {

                    $(".myEmoji").hide();
                }
            });


        });


        //将表情添加到输入框
        // each() 方法规定为每个匹配元素规定运行的函数。
        $(".myEmoji img").each(function () {
            $(this).click(function () {
                var url = $(this)[0].src;
                $('#content').append("<img src='" + url + "' style='width:25px;height:25px' >");
                $("#send").removeClass("disabled");
            })
        });


        //放大或缩小预览图片
        $(".mypic").click(function () {
            var oWidth = $(this).width(); //取得图片的实际宽度
            var oHeight = $(this).height(); //取得图片的实际高度

            if ($(this).height() != 200) {
                $(this).height(200);
            } else {
                $(this).height(oHeight + 200 / oWidth * oHeight);

            }

        })
    });
</script>
</body>
</html>

在这里插入图片描述
login界面如图;

<!DOCTYPE html>
<html>
<head>
<title>登录页面</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

{#    两种方式任选一种 #}
{#<link href="../static/css/login.css" rel="stylesheet" type="text/css" media="all" />#}
<link href="{{ url_for('static', filename='css/login.css' ) }}" rel="stylesheet" type="text/css" media="all" />
{# url_for('静态文件存在的目录位置',filename='文件名')根据提供的信息,给生成一个url地址#}
</head>
<body>

	<!-- main -->
	<div class="main-w3layouts wrapper">
		<div class="main-agileinfo">
			<div class="agileits-top">
				<form action="/login/" method="post">
                    {#         required="": 用户名不能为空           #}
					<input class="text" type="text" name="username" placeholder="用户名" required="">
					<input class="text" type="password" name="password" placeholder="密码" required="">
					<div class="wthree-text">
						<ul>
							<li>
								<label class="anim">
									<input type="checkbox" class="checkbox" >
									<span> 记住 ?</span>
								</label>
							</li>
							<li><a href="#">忘记密码 ?</a> </li>
						</ul>
						<div class="clear"> </div>
					</div>
					<input type="submit" value="登录">
                    <p style="color: red;">{{ get_flashed_messages() }}</p>
                        {#get_flashed_messages() 默认返回的是一个列表#}
				</form>
				<p>创建一个账号? <a href="/register/"> 立即注册!</a></p>
			</div>
		</div>
		<!-- copyright -->
		<div class="w3copyright-agile">
			<p>© 2019 西部开源</p>
		</div>
		<!-- //copyright -->
		<ul class="w3lsg-bubbles">
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
		</ul>
	</div>
	<!-- //main -->

</body>
</html>

在html文件中,外联法调用css文件时,动态获取css文件有两种方法:
(1)
(2)
{{ url_for(‘static’, filename = ‘style.css’)}} // 根据提供的信息生成一个静态的url
在这里插入图片描述
register界面;

<!DOCTYPE html>
<html>
<head>
<title>登录页面</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

{#    两种方式任选一种 #}
{#<link href="../static/css/login.css" rel="stylesheet" type="text/css" media="all" />#}
<link href="{{ url_for('static', filename='css/login.css' ) }}" rel="stylesheet" type="text/css" media="all" />
{# url_for('静态文件存在的目录位置',filename='文件名')根据提供的信息,给生成一个url地址#}
</head>
<body>

	<!-- main -->
	<div class="main-w3layouts wrapper">
		<div class="main-agileinfo">
			<div class="agileits-top">
				<form action="/register/" method="post">
                    {#         required="": 用户名不能为空           #}
					<input class="text" type="text" name="username" placeholder="用户名" required="">
					<input class="text" type="password" name="password" placeholder="密码" required="">
					<div class="wthree-text">
						<ul>
							<li>
								<label class="anim">
									<input type="checkbox" class="checkbox" >
									<span> 记住 ?</span>
								</label>
							</li>
							<li><a href="#">忘记密码 ?</a> </li>
						</ul>
						<div class="clear"> </div>
					</div>
					<input type="submit" value="注册">
                    <p style="color: red;">{{ get_flashed_messages() }}</p>
				</form>
				<p>已有账号? <a href="/login/"> 立即登陆!</a></p>
			</div>
		</div>
		<!-- copyright -->
		<div class="w3copyright-agile">
			<p>© 2019 西部开源</p>
		</div>
		<!-- //copyright -->
		<ul class="w3lsg-bubbles">
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
			<li></li>
		</ul>
	</div>
	<!-- //main -->

</body>
</html>

在这里插入图片描述
app.py

from flask import Flask, request, render_template, redirect, flash, session

# from util import is_login
from util.is_login import is_login

app = Flask(__name__)
app.config["SECRET_KEY"] = "WESTOS" #加密盐
users = [
    {
        'username':'root',
        'password':'westos',
    },
    {
        'username':'user1',
        'password':'user1',
    }
]
@app.route('/')
def index():
    return render_template('index.html')
@app.route('/login/',methods=['GET','POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    # request请求方法是post
    else:
        # 获取post提交的数据
        username = request.form.get('username')
        password = request.form.get('password')
        for user in users:
            if user['username']==username and user['password'] == password:
                # 存储用户登陆信息:session可以认为是字典对象
                session['username'] = username
                print(session)
                print(users)
                flash('登陆成功')
                return redirect('/')
        else:
            flash("登陆失败")
            return render_template('login.html')
@app.route('/logout/')
def logout():
    session.pop('username')
    print(session)
    flash('注销成功')
    return redirect('/login/')
@app.route('/register/',methods=['GET','POST'])
def register():
    """
    1).http请求的方法为get方法,直接返回注册页面
    2).http请求的方法为post方法,
        - 注册的用户名是否已经存在
        - 如果不存在,则存储用户名和密码到数据库
    :return:
    """
    if request.method == 'GET':
        return render_template('register.html')
    else:
        username = request.form.get('username')
        password = request.form.get('password')
        for user in users:
            # 如果用户名存在则重新注册
            if user['username'] == username:
                flash('注册失败,用户名重复')
                return redirect('/register/')
        else:
            # 如果不存在,存储用户名和密码到数据库中
            users.append({'username':username,'password':password})
            flash("用户注册成功,请登陆")
            return redirect('/login/')
@app.route('/list/<int:page>')
def list(page):
    return render_template('list.html',users=users)
@app.route('/bbs/')
@is_login
def bbs():
    return 'bbs'
@app.route('/blog/')
@is_login
def blog():
    return 'blog'

if __name__ == '__main__':
    app.debug = True
    app.run()

Flask中静态文件介绍

动态的 web 应用也需要静态文件,一般是 CSS , 图片和 JavaScript 文件。理想情况下你的 服务器已经配置好了为你的提供静态文件的服务。
静态文件存储位置
在开发过程中, Flask 静态文件位于应用的 /static 目录中。
调用方式:

#静态文件在文件系统中的位置应该是 static/style.css 。
{{ url_for(‘static’, filename=‘style.css’) }}

会话session介绍

session 的对象,允许你在不同请求之间储存信息。这个对象相当于用密钥签名加密的 cookie , 即用户可以查看你的 cookie,但是如果没有密钥就无法修改它。

注:使用会话之前你必须设置一个密钥。

#Set the secret key to some random bytes. Keep this really secret!
app.secret_key = b’_5#y2L"F4Q8z\n\xec]/’

flash消息闪现介绍

什么是消息闪现?
消息闪现就是只展示一次的数据/参数.
Flask 提供了一个非常简单的方法来使用闪现系统向用户反馈信息。闪现系统使得在一个请求结束的时候记录一个信息, 然后在且仅仅在下一个请求中访问这个数据。Flask消息闪现可以给用户更好的体验。

应用场景:

  • 上传图片代码,加入消息闪现功能。
  • 进入首页只刷一次的广告。
  • 用户登录成功的闪现信息。
  • 用户登录失败的闪现信息。
  • 用户注册成功的闪现信息。
  • 用户注册失败的闪现信息。

实现步骤:

  • 引入一个函数 flash,用于存储你究竟都有哪些信息需要展示

from flask import flash

  • 使用flash保存,它实际上是暂时帮我们保存在session里面, 存储时需要加密

app.config[“SECRET_KEY”] = “westos”

  • Flask后台中存储闪现信息

flash(“要展示的闪现信息”)

  • 前端页面获取闪现信息

{{ get_flashed_messages() }}

前端html获取后台信息的方法有
1、session 获取后台存入session中的内容,直接通过session.username来获取
2、get_flashed_messages() 获取闪现信息
3、request 获取请求头部
4、g 获取后台所有全局变量

flash提升:分类闪现
分类闪现,当闪现一个消息时,是可以提供一个分类的。这更符合我们实际开发中的场景,例如,

  • 当文件上传成功时,我们提示消息“photo upload success”为绿色;
  • 当上传文件失败时,我们提示消息“photo upload error”为红色。
    Flask后台中存储闪现信息

flash(“photo upload success”, “success”)
flash(“photo upload error”, “error”)

前端页面获取闪现信息

{% with messages = get_flashed_messages(category_filter=[‘success’])%}
{% if messages %}


  • {% for message in messages %}
  • {{ message }}

  • {% endfor %}

{% endif %}
{% endwith %}
{% with messages = get_flashed_messages(category_filter=[‘error’])%}
{% if messages %}

  • {% for message in messages %}
  • {{ message }}

  • {% endfor %}

{% endif %}
{% endwith %}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值