• 【Python百日进阶-WEB开发-冲進Flask】Day182 - Flask蓝图与模板继承


    一、day02项目环境和结构搭建

    1.1 项目根目录创建apps包

    包内包含__init__.py文件

    1.2 项目模板目录templates创建user子目录

    user子应用中用到的页面 html 文件全部放到 templates\user 子目录中。

    二、后端知识要点

    2.1 蓝图Blueprint基础知识

    2.1.1 为什么需要蓝图

    随着flask程序越来越复杂,我们需要对程序进行模块化的处理,以利于大项目的开发。

    2.1.2 什么是蓝图

    • 蓝图(blueprint):是flask自带的一种开发模式,用于实现单个应用的视图、模板、静态文件的集合。
    • 蓝图就是模块化处理的类,类似于Django中的app-子应用。
    • 蓝图就是一个存储操作路由映射方法的容器,主要用来实现客户端请求和URL相互关联的功能。 在Flask中,使用蓝图可以帮助我们实现模块化应用的功能。

    2.1.3 蓝图的属性

    • 一个项目可以具有多个Blueprint。
    • 可以将一个Blueprint注册到任何一个未使用的URL下比如 “/”、“/sample”或者子域名。
    • 在一个应用中,一个模块可以注册多次。
    • Blueprint可以单独具有自己的模板、静态文件或者其它的通用操作方法,它并不是必须要实现应用的视图和函数的。
    • 在一个应用初始化时,就应该要注册需要使用的Blueprint。

    2.1.4 蓝图使用的步骤

    2.1.4.1 创建一个蓝图的包,例如user,并在view.py文件中创建蓝图对象
    from flask import Blueprint
    user_bp = Blueprint('user', __name__)
    
    • 1
    • 2
    2.1.4.2 view.py文件中创建当前蓝图使用的视图函数
    • 使用蓝图后,反向解析url_for()需要用蓝图的名称点出路由别名。
    • 使用蓝图后,模板渲染需要从templates文件夹开始指定html文件目录,可能包括多层目录。
    @user_bp.route('/')
    def user_center():
        # print(url_for('user.register'))     # 反向解析需要加上蓝图名称
        return render_template('user/show.html', users=users)
    
    • 1
    • 2
    • 3
    • 4
    2.1.4.3 apps包的初始化文件__init__.py中新建创建应用app的函数,并绑定蓝图
    • 因为创建蓝图,改变了Flask默认目录结构,所以初始化app时需要重新指定模板和静态文件目录。
    • 蓝图必须在初始化app时绑定到app上,才能发挥作用。
    from flask import Flask
    import settings
    from apps.user.view import user_bp
    
    def create_app():
        app = Flask(__name__,
                    template_folder='../templates',
                    static_folder='../static',
                    )
        app.config.from_object(settings)
        # 将蓝图对象绑定到app
        app.register_blueprint(user_bp)
        print(app.url_map)
        return app
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    2.1.4.4 项目根目录app.py调用函数创建app对象
    • 调用函数创建app对象可以保持启动文件的干净、清爽。
    from apps import create_app
    
    app = create_app()
    
    if __name__ == '__main__':
        app.run(port=5002)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.2 request对象获取前端提交的数据

    2.2.1 接收前端两种方式提交的数据

    • 蓝图路由中添加参数:methods=[‘GET’, ‘POST’]
    • 反向解析默认的名称为函数名(如user_update);如果函数名较长,可以指定别名endpoint=‘update’。
    • 每种方式都必须有返回值,否则会报错。
    @user_bp.route('/update', methods=['GET', 'POST'], endpoint='update')
    def user_update():
        if request.method == 'POST':
            # 获取post提交的数据
            username = request.form.get('username')
            return redirect('/')
        if request.method == 'GET':
    	    # 获取get提交的数据
    	    username = request.args.get('username')
    	    return render_template('user/update.html')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.2.2 获取前端get方式提交的数据

    • get(‘username’) 与前端的 name='username’对应
    username = request.args.get('username')
    
    • 1

    2.2.3 获取前端post方式提交的数据

    username = request.form.get('username')
    
    • 1

    2.3 model.py定义类

    2.3.1 User类的定义

    • 注意:类名首字母大写
    class User:
        def __init__(self, username, password, phone=None):
            self.username = username
            self.password = password
            self.phone = phone
    
        def __str__(self):
            return self.username
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.3.2 User类的实例化

    • 注意:类名首字母大写
    from apps.user.model import User
    user = User(username, password, phone)
    
    • 1
    • 2

    三、前端知识要点

    3.1 HTML页面文件的结构安排

    • 基础母版文件base.html放到模板文件夹中:day02\templates
    • user子应用的html文件放到模板文件夹的下级目录中:day02\templates\user

    3.2 创建基础母版模板base.html

    1. html框架
    2. 预留标题block(title)
    3. 预留css样式block(mycss)
    4. 预留页面顶端block(head)
    5. 预留页面中部主体block(middel)
    6. 预留页面尾部block(foot)
    7. 预留javascript block(myjs)
    DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>{% block title %} 用户中心 {% endblock %}title>
    		{% block mycss %}
    		{% endblock %}
    	head>
    	<body>
    		<div id="head">
    			<ul>
    				<li><a href="">首页a>li>
    				<li><a href="">秒杀a>li>
    				<li><a href="">超市a>li>
    				<li><a href="">图书a>li>
    				<li><a href="">会员a>li>
    			ul>
    			{% block head%}{% endblock %}
    		div>
    		
    		<div id="middle">
    			{% block middle %}{% endblock %}
    		div>
    		
    		<div id="foot">
    			{% block foot%}{% endblock %}
    		div>
    		
    		{% block myjs %}{% endblock %}
    	body>
    html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    3.3 模板的继承

    3.3.1 继承基础母版base.html

    • {% extends ‘base.html’ %} 一般放在子页面的第一行
    • 项目所有html文件的起始查找目录,都是基于app初始化时的templates文件夹
    {% extends 'base.html' %}
    
    • 1

    3.3.2 Block填坑

    {% block title %}
    	用户展示
    {% endblock %}
    
    {% block middle %}
    	<span>当前用户人数时:{{ users|length }} 人span>
    	
    	<ul>
    		{% for user in users %}
    			<li>{{user.username}}-{{user.password}}-{{user.phone}}li>
    		{% endfor %}
    	ul>
    	<table border="solid 1" cellspacing="0" width="60%">
    		{% for user in users %}
    			<tr>
    				<td>{{ loop.index }}td>
    				<td>{{ user.username }}td>
    				<td>{{ user.password }}td>
    				<td>{{ user.phone }}td>
    				<td><a href="javascript:;" onclick="update('{{ user.username }}')">修改a>
    				<a href="javascript:;" onclick="del('{{ user.username }}')">删除a>td>
    			tr>
    		{% endfor %}
    	table>
    {% endblock %}
    
    {% block myjs %}
    	<script type="text/javascript">
    		function del(username){
    			// console.log(username)
    			// location 地址栏对象
    			location.href = '/del?username=' + username
    		}
    		
    		function update(username){
    			location.href = '/update?username=' + username
    		}
    	script>
    {% endblock %}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    3.4 取消超链接href,自定义js

    • href=“javascript:;” 为取消超链接
    • οnclick=“del(‘{{ user.username }}’)” 为自定义js函数名称,特别注意:参数如果为字符串,需要双层引号。
    • js函数参数接收和python相同,放到圆括号中。
    • js中,location.href相当于重定向,可以拼接 路由 + ? + 变量名=value
    <a href="javascript:;" onclick="del('{{ user.username }}')">删除a>
    
    <script type="text/javascript">
    	function del(username){
    		// console.log(username)
    		// location 地址栏对象
    		location.href = '/del?username=' + username
    	}
    script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    四、项目完整代码

    4.1 项目目录结构

    在这里插入图片描述

    4.2 后端代码

    4.2.1 配置文件settings.py

    # 配置文件
    
    ENV = 'development'
    DEBUG = True
    
    • 1
    • 2
    • 3
    • 4

    4.2.2 项目启动app.py

    from apps import create_app
    
    app = create_app()
    
    if __name__ == '__main__':
        app.run(port=5002)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.2.3 user包初始化__init__.py

    from flask import Flask
    import settings
    from apps.user.view import user_bp
    
    def create_app():
        app = Flask(__name__,
                    template_folder='../templates',
                    static_folder='../static',
                    )
        app.config.from_object(settings)
        # 将蓝图对象绑定到app
        app.register_blueprint(user_bp)
        print(app.url_map)
        return app
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.2.4 user子应用model.py

    class User:
        def __init__(self, username, password, phone=None):
            self.username = username
            self.password = password
            self.phone = phone
    
        def __str__(self):
            return self.username
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.2.5 user子应用视图view.py

    from flask import Blueprint, request, render_template, redirect, url_for
    from apps.user.model import User
    
    user_bp = Blueprint('user', __name__)
    
    # 列表保存用户对象
    users = []
    
    @user_bp.route('/')
    def user_center():
        # print(url_for('user.register'))     # 反向解析需要加上蓝图名称
        return render_template('user/show.html', users=users)
    
    @user_bp.route('/register', methods=['GET', 'POST'])
    def register():
        if request.method == 'POST':
            # 获取post提交的数据
            username = request.form.get('username')
            password = request.form.get('password')
            repassword = request.form.get('repassword')
            phone = request.form.get('phone')
            if password == repassword:
                # 保证用户名唯一
                for user in users:
                    if user.username == username:
                        msg = '用户名已存在!'
                        print(msg)
                        return render_template('user/register.html', msg=msg)
                    #4.4蓝图1:04:35
                # 创建user对象
                user = User(username, password, phone)
                # 添加到用户列表
                users.append(user)
                # print(users)
                return redirect('/')
            else:
                return render_template('user/register.html', msg='密码不一致!')
        return render_template('user/register.html')
    
    @user_bp.route('/login', methods=['GET', 'POST'])
    def login():
        return '用户登录'
    
    @user_bp.route('/logout', methods=['GET', 'POST'])
    def logout():
        return '用户退出'
    
    @user_bp.route('/del')
    def del_user():
        # 获取传递过来的username
        username = request.args.get('username')
        # 根据username找到列表中的对象
        for user in users:
            if user.username == username:
                users.remove(user)
                return redirect('/')
        else:
            return '删除失败'
    
    @user_bp.route('/update', methods=['GET', 'POST'], endpoint='update')
    def user_update():
        if request.method == 'POST':
            # post请求
            realname = request.form.get('realname')
            username = request.form.get('username')
            password = request.form.get('password')
            phone = request.form.get('phone')
            # 判断用户名是否重复
            for user in users:
                if user.username == username:
                    return render_template('user/update.html', msg='用户名重复!')
            else:
                for user in users:
                    if user.username == realname:
                        user.username = username
                        user.phone = phone
                        return redirect('/')
        else:
            # get请求
            username = request.args.get('username')
            for user in users:
                # 匹配用户
                if user.username == username:
                    return render_template('user/update.html', user=user)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    4.3 前端代码

    4.3.1 项目基础母版base.html

    DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>{% block title %} 用户中心 {% endblock %}title>
    		<style type="text/css">
    			#head {
    				height: 3.125rem;
    				background-color: bisque;
    			}
    			
    			#head ul li {
    				float: left;
    				width: 6.25rem;
    				text-align: center;
    				font-size: 1.125rem;
    				height: 3.125rem;
    				line-height: 3.125rem;
    			}
    			
    			#middle {
    				height: 56.25rem;
    				background-color: azure;
    			}
    			
    			#foot {
    				height: 3.125rem;
    				line-height: 3.125rem;
    				background-color: darkseagreen;
    			}
    		style>
    		{% block mycss %}
    		{% endblock %}
    	head>
    	<body>
    		<div id="head">
    			<ul>
    				<li><a href="">首页a>li>
    				<li><a href="">秒杀a>li>
    				<li><a href="">超市a>li>
    				<li><a href="">图书a>li>
    				<li><a href="">会员a>li>
    			ul>
    		div>
    		
    		<div id="middle">
    			{% block middle %}{% endblock %}
    		div>
    		
    		<div id="foot">
    			
    		div>
    		
    		{% block myjs %}
    		{% endblock %}
    	body>
    html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    4.3.2 user子应用注册页面register.html

    {% extends 'base.html' %}
    {% block title %}
    	用户注册
    {% endblock %}
    
    {% block middle %}
    	<p style="color: red">	{{ msg }}p>
    	<form action="{{ url_for('user.register') }}" method="post">
    		<p><input type="text" name="username" placeholder="用户名">p>
    		<p><input type="password" name="password" placeholder="密码">p>
    		<p><input type="password" name="repassword" placeholder="确认密码">p>
    		<p><input type="number" name="phone" placeholder="手机号码">p>
    		<p><input type="submit" value="用户注册">p>
    	form>
    
    {% endblock %}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    4.3.3 user子应用用户展示页面

    {% extends 'base.html' %}
    {% block title %}
    	用户展示
    {% endblock %}
    
    {% block middle %}
    	<span>当前用户人数时:{{ users|length }} 人span>
    	
    	<ul>
    		{% for user in users %}
    			<li>{{user.username}}-{{user.password}}-{{user.phone}}li>
    		{% endfor %}
    	ul>
    	<table border="solid 1" cellspacing="0" width="60%">
    		{% for user in users %}
    			<tr>
    				<td>{{ loop.index }}td>
    				<td>{{ user.username }}td>
    				<td>{{ user.password }}td>
    				<td>{{ user.phone }}td>
    				<td><a href="javascript:;" onclick="update('{{ user.username }}')">修改a>
    				<a href="javascript:;" onclick="del('{{ user.username }}')">删除a>td>
    			tr>
    		{% endfor %}
    	table>
    {% endblock %}
    
    {% block myjs %}
    	<script type="text/javascript">
    		function del(username){
    			// console.log(username)
    			// location 地址栏对象
    			location.href = '/del?username=' + username
    		}
    		
    		function update(username){
    			location.href = '/update?username=' + username
    		}
    	script>
    {% endblock %}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    在这里插入图片描述

    4.3.4 user子应用用户更新页面update.html

    {% extends 'base.html' %}
    
    {% block title %}
    	用户信息修改
    {% endblock %}
    
    {% block middle %}
    	<h1>用户信息更新h1>
    	<p style="color: red">	{{ msg }}p>
    	<form action="{{ url_for('user.update') }}" method="post">
    		<p><input type="hidden" name="realname" id="" value="{{ user.username }}" />p>
    		<p><input type="text" name="username" placeholder="用户名" value="{{ user.username }}">p>
    		<p><input type="text" name="password" placeholder="密码" value="{{ user.password }}" disable>p>
    		<p><input type="number" name="phone" placeholder="手机号码" value="{{ user.phone }}">p>
    		<p><input type="submit" value="用户更新">p>
    	form>
    {% endblock %}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    DC3算法(后缀数组生成)
    智慧箱变动环辅控系统
    打地鼠(susliks) 方法记录
    XGboost遥感gis数据的回归预测(复合结果预测, 多列预测)实践(python版)
    eclipse中tomcat部署路径
    Linux下的编辑器——Vim
    【2022 CCF BDCI 文心大模型创意项目】中秋款文心带你轻松搞定MV制作
    Opencv 极坐标变换
    运行主程序后无法显示图形化界面的原因及其解决方法(拼图小游戏)
    WordPress主题开发( 十四)之—— 主题开发示例
  • 原文地址:https://blog.csdn.net/yuetaope/article/details/122875579