基于Flask实现一个更加美观的用户登录界面,包括登录,注册,消息闪现,模板继承,文件包含以及Jinja2语法。

1、创建一个Flask项目:

python flask 登录界面 flask实现登录_css


通常我们将html文件放在templates文件夹中,将静态文件,比如css文件,js文件,字体,图片放在static文件夹中。

2、主程序app.py

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

# from Flask.UserManager.utils.is_login import is_login
# from UserManager.utils.is_login import is_login
from utils.is_login import is_login

app = Flask(__name__)

# flash的消息都存储在session,需要一个会话密匙,密匙随便输入就行,如果对保密性要求高的话,可以使用相关的密匙生成函数
app.config["SECRET_KEY"] = "westos"  # 加密盐

users = [
    {
        'username':'root',
        'password':'root'
    }
]
# 会话: session
# 缓存: cookie

@app.route('/bbs/')
@is_login
def bbs():
    return 'bbs'

@app.route('/blog/')
@is_login
def blog():
    return 'blog'

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


@app.route('/login/', methods=['GET', 'POST'])
def login():
    # get直接读取填写的数据
    if request.method == 'GET':
        return  render_template('login.html')
    # request.method=='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)
                flash("登录成功")
                return redirect('/')
        else:
            flash("登录失败",category='error')
            return render_template('login.html', errMessages='login fail')

@app.route('/logout/')
def logout():
    # 将session中的用户信息删除;
    session.pop('username')
    flash("注销成功")
    return  redirect('/login/')

@app.route('/register/', methods=['GET', 'POST'])
def register():
    """
    1), http请求的方法为get方法, 直接返回注册页面;
    2). http请求的方法为post方法,
        - 注册的用户名是否已经存在, 如果存在, 重新注册;
        - 如果不存在, 存储用户名和密码到数据库中;
    """
    if request.method == 'GET':
        return  render_template('register.html')
    else:
        # 获取post提交的数据
        username = request.form.get('username')
        password = request.form.get('password')
        for user in users:
            # 注册的用户名是否已经存在, 如果存在, 重新注册;
            if user['username'] == username:
                flash("注册失败: 用户名冲突")
                # session['username'] = username
                return redirect('/register/')
        # 如果不存在, 存储用户名和密码到数据库中;
        else:
            users.append(dict(username=username, password=password))
            flash("用户注册成功, 请登录")
            return  redirect('/login/')

@app.route('/list/<int:page>/') # 用户信息的分页查看
def list(page):
    return  render_template('list.html', users=users)


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

3、写完主程序之后,在来写html页面:

首先是login.html文件

<!DOCTYPE html>
<html lang="en">
<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="../static/css/login.css" rel="stylesheet" type="text/css" media="all" />

</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="登录">
                    {% for msg in get_flashed_messages() %}
                        <p style="color: red;">{{ msg }}</p>
                    {% endfor %}
				</form>
				<p>创建一个账号? <a href="/register/"> 立即注册!</a></p>
			</div>
		</div>

		<div class="w3copyright-agile">
			<p>© 2020 西部开源</p>
		</div>

		<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>

闪现消息的创建和接收: 在主程序中flash(message)—>在html文档中{{ get_flashed_message }}接收闪现消息。flash的消息都存储在session,需要一个会话密匙,密匙随便输入就行。

注册页面:register.html
注册页面在登陆页面的基础上稍加改正。

<!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"/>

</head>
<body>

<!-- main -->
<div class="main-w3layouts wrapper">
    <div class="main-agileinfo">
        <div class="agileits-top">
            <form action="/register/" method="post">
                <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" required="">#}
                        {#									<span> 记住 ?</span> #}
                        {#								</label> #}
                        {#							</li>#}
                        <li><a href="#">忘记密码 ?</a></li>
                    </ul>
                    <div class="clear"></div>
                </div>

                <input type="submit" value="注册">
                {% for msg in get_flashed_messages() %}
                <P style="color: red">{{ msg }}</P>
                {% endfor %}
            </form>
            <p>已有账号? <a href="/login/"> 立即登录!</a></p>
        </div>
    </div>
    <!-- copyright -->
    <div class="w3copyright-agile">
        <p>© 2020 西部开源</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>

效果如图:

python flask 登录界面 flask实现登录_用户名_02


分页显示用户信息–list.html

{% extends 'base.html' %}


{% block title %} 用户列表{% endblock %}


{% block body %}
    <h1>用户信息</h1>
    <table width="80%" align="center" style="margin-top: 50px">
        <tr>
            <td>用户名</td>
            <td>密码</td>
        </tr>
        {% for user in users %}
            <tr>
                <td>{{ user.username }}</td>
                <td>{{ user.password }}</td>
            </tr>


        {% endfor %}


    </table>

{% endblock %}

list.html继承了base.html,base.html文件如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %}</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>  {{ 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>


{% block body %}


{% endblock %}


</body>
</html>

主页样式–index.html

<!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>  {{ 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="imgPath">图片</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.png" 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.png">
                <h4 style="font-weight: bold;">Westos</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 != ".PNG" && postfix != ".JPG" && postfix != ".GIF" && postfix != ".JPEG") {
                    alert("图片格式需为png,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.png' 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.png' 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 + ".png' style='width:35px;height:35px' >");
        }
        //添加表情包2
        for (var i = 1; i < 61; i++) {
            $(".emoji_2").append("<img src='img/h" + i + ".png' 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>

主页样式如图:

python flask 登录界面 flask实现登录_用户名_03


用户登录之后的显示界面如下:

python flask 登录界面 flask实现登录_html_04

完整代码可访问:https://github.com/wtwdy/UserManager–,包括相关js和css文件。