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

news2025/8/13 14:36:43

文章目录

  • 一、day02项目环境和结构搭建
    • 1.1 项目根目录创建apps包
    • 1.2 项目模板目录templates创建user子目录
  • 二、后端知识要点
    • 2.1 蓝图Blueprint基础知识
      • 2.1.1 为什么需要蓝图
      • 2.1.2 什么是蓝图
      • 2.1.3 蓝图的属性
      • 2.1.4 蓝图使用的步骤
        • 2.1.4.1 创建一个蓝图的包,例如user,并在view.py文件中创建蓝图对象
        • 2.1.4.2 view.py文件中创建当前蓝图使用的视图函数
        • 2.1.4.3 apps包的初始化文件__init__.py中新建创建应用app的函数,并绑定蓝图
        • 2.1.4.4 项目根目录app.py调用函数创建app对象
    • 2.2 request对象获取前端提交的数据
      • 2.2.1 接收前端两种方式提交的数据
      • 2.2.2 获取前端get方式提交的数据
      • 2.2.3 获取前端post方式提交的数据
    • 2.3 model.py定义类
      • 2.3.1 User类的定义
      • 2.3.2 User类的实例化
  • 三、前端知识要点
    • 3.1 HTML页面文件的结构安排
    • 3.2 创建基础母版模板base.html
    • 3.3 模板的继承
      • 3.3.1 继承基础母版base.html
      • 3.3.2 Block填坑
    • 3.4 取消超链接href,自定义js
  • 四、项目完整代码
    • 4.1 项目目录结构
    • 4.2 后端代码
      • 4.2.1 配置文件settings.py
      • 4.2.2 项目启动app.py
      • 4.2.3 user包初始化__init__.py
      • 4.2.4 user子应用model.py
      • 4.2.5 user子应用视图view.py
    • 4.3 前端代码
      • 4.3.1 项目基础母版base.html
      • 4.3.2 user子应用注册页面register.html
      • 4.3.3 user子应用用户展示页面
      • 4.3.4 user子应用用户更新页面update.html

一、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__)

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)

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

2.1.4.4 项目根目录app.py调用函数创建app对象

  • 调用函数创建app对象可以保持启动文件的干净、清爽。
from apps import create_app

app = create_app()

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

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

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

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

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

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

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

2.3.2 User类的实例化

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

三、前端知识要点

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>

3.3 模板的继承

3.3.1 继承基础母版base.html

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

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

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>

四、项目完整代码

4.1 项目目录结构

在这里插入图片描述

4.2 后端代码

4.2.1 配置文件settings.py

# 配置文件

ENV = 'development'
DEBUG = True

4.2.2 项目启动app.py

from apps import create_app

app = create_app()

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

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

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

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)

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>

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

在这里插入图片描述

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

在这里插入图片描述

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/33283.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝牙耳机什么牌子音质最好?音质超好的蓝牙耳机推荐

蓝牙耳机在便捷性上&#xff0c;没有线材的蓝牙耳机&#xff0c;日常通勤、运动、平时走路佩戴&#xff0c;那种因为无线而带来的无缠绕感觉都是有线耳机无法媲美的&#xff0c;但是音质很多人都会觉得有线的好&#xff0c;由于近几年耳机市场的不断进步&#xff0c;很多蓝牙耳…

《痞子衡嵌入式半月刊》 第 67 期

痞子衡嵌入式半月刊&#xff1a; 第 67 期 这里分享嵌入式领域有用有趣的项目/工具以及一些热点新闻&#xff0c;农历年分二十四节气&#xff0c;希望在每个交节之日准时发布一期。 本期刊是开源项目(GitHub: JayHeng/pzh-mcu-bi-weekly)&#xff0c;欢迎提交 issue&#xff0c…

8-Arm PEG-Azide,8-Arm PEG-N3,八臂-聚乙二醇-叠氮多臂PEG衍生物供应

1、名称 英文&#xff1a;8-Arm PEG-Azide&#xff0c;8-Arm PEG-N3 中文&#xff1a;八臂-聚乙二醇-叠氮 2、CAS编号&#xff1a;N/A 3、所属分类&#xff1a;Azide PEG Multi-arm PEGs 4、分子量&#xff1a;可定制&#xff0c;八臂-peg 5k-叠氮、八臂PEG 2k叠氮、叠氮-…

卷积神经网络

Datawhale开源学习&#xff0c;机器学习课程&#xff0c;项目地址&#xff1a;https://github.com/datawhalechina/leeml-notes Convolutional Neural Network 本节内容学习了什么是CNN卷积神经网络&#xff0c;相比于全连接网络&#xff0c;它每次只提取部分内容作为整个网络…

专利如果申请?成功率如何提高?

问题一&#xff1a;专利如何申请&#xff1f;​ 1、整理技术方案&#xff0c;整理一套属于你的创新技术方案&#xff1b; 2、专利检索&#xff0c;确保你的创新没有被别人申请过&#xff1b; 3、撰写专利申请书&#xff0c;为了快速审查&#xff0c;做好长期专利布局&#x…

珈创生物上市再次失败:先后折戟科创板、创业板,郑从义为董事长

第二次冲刺上市之旅&#xff0c;珈创生物再次以失败而告终。 11月23日&#xff0c;深圳证券交易所创业板披露的信息显示&#xff0c;因武汉珈创生物技术股份有限公司&#xff08;即“珈创生物”&#xff09;提交了撤回首次公开发行股票并在创业板上市申请文件的申请&#xff0…

医院微信预约挂号小程序开发_分享医院做预约挂号小程序的可以实现什么功能

小程序有 60入口&#xff0c;在微信生态链中无处不在&#xff0c;只要客户是微信用户&#xff0c;他们可以根据搜索、二维码朋友圈找到你的小程序。哪怕是医药行业&#xff0c;也可以做个医院小程序来提高预约和经营运转的效率&#xff0c;解放人力。 1.医院微信预约小程序怎么…

ubuntu下个人觉得必备,好用的应用软件

ubuntu下个人觉得必备&#xff0c;好用的应用软件 本文基于ubuntu20.04 进行讨论。 之前用了很久ubuntu14.04&#xff0c; 因为apt安装依赖的问题&#xff0c;导致系统重装&#xff0c;才被动升级到了20.04. 结果升级后发现了新大陆。 很多原来只能在windows下使用的软件&…

【多目标进化优化】 Pareto 最优解集的构造方法

1. 构造 Pareto 最优解的简单方法 1.1 Deb 的非支配排序方法 \quad\quad设进化群体为 PPP&#xff0c;同时设置一个构造集 P′PP′。算法开始时将第一个个体放人构造集 P′PP′ 中&#xff0c;依次将进化群体 PPP 中的个体 p&#xff08;p∉P′&#xff09;p&#xff08;p∉P&…

护航“东数西算”工程 | 安全狗云原生安全能力亮相2022南京软博会

11月23日&#xff0c;2022中国&#xff08;南京&#xff09;国际软件产品和信息服务交易博览会&#xff08;简称“2022南京软博会”&#xff09;下的“东数西算”助力数字经济协同发展论坛在南京国际博览中心顺利举办。安全狗也收到邀请出席此次活动。 据悉&#xff0c;此次活…

Flink 结合 HyperScan 问题记录

最近工作需要对公司业务大规模日志进行处理&#xff0c;需要进行通过正则预先匹配出符合条件的日子&#xff0c;经过调研Hyperscan符合预期。 如何提高大规模正则匹配的效能_360技术的博客-CSDN博客 Hyperscan是一款来自于Intel的高性能的正则表达式匹配库。它是基于X86平台以P…

SystemFunction032函数的免杀研究

什么是SystemFunction032函数&#xff1f; 虽然Benjamin Delphi在2013年就已经在Mimikatz中使用了它&#xff0c;但由于我之前对它的研究并不多&#xff0c;才有了下文。 这个函数能够通过RC4加密方式对内存区域进行加密/解密。例如&#xff0c;ReactOS项目的代码中显示&…

(附源码)计算机毕业设计JavaJava毕设项目补课管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis Maven Vue 等等组成&#xff0c;B/…

(六)RabbitMQ第二种模型:工作模型(Work Queues)

工作模型&#xff08;Work Queues&#xff09;一、轮询发送消息二、消息应答2.1、概念2.2、自动应答2.3、手动应答2.4、消息的重新入队2.5、手动应答代码概念&#xff1a;工作队列(又称任务队列)的主要思想是避免立即执行资源密集型任务&#xff0c;而不得不等待它完成。 相反我…

为什么说 Windows 10 不会被 DDoS SSDP反射攻击利用

为什么说 Windows 10 不会被 DDoS SSDP反射攻击利用一段来自陌生人的对话我所在网络拓扑图一、SSDP 协议极简介绍二、模拟查找 SSDP 设备2.1 Linux 发现 SSDP 服务2.2 Windows 发现 SSDP 服务三、Windows 10 VS Windows 7 数据包四、回答先前的问题回答 1&#xff1a;Windows 1…

前后端分离项目,vue+uni-app+php+mysql订座预约小程序系统设计与实现

功能介绍 【后台功能】 广告管理&#xff1a;设置小程序首页轮播图广告和链接 留言列表&#xff1a;所有用户留言信息列表&#xff0c;支持删除 会员列表&#xff1a;查看所有注册会员信息&#xff0c;支持删除 录入资讯&#xff1a;录入资讯标题、内容等信息 管理资讯&#x…

证书格式说明

证书格式说明 参考&#xff1a; 证书格式说明SSL中&#xff0c;公钥、私钥、证书的后缀名都是些啥&#xff1f; PEM 参考&#xff1a; Pem格式 Privacy-Enhanced Mail (PEM)是存储、传输密码学的密钥、公开密钥证书和其他数据的文件格式的业界标准。 许多加密标准使用ASN.1…

几行 Python 代码就可以提取数百个时间序列特征

以下所有内容均来自python绿色通道订阅号&#xff0c;个人整理主要为了个人方便查看&#xff0c;希望也可以对各位有所帮助 时间序列数据是随着时间的推移反复捕获的变量值&#xff0c;随着时间的推移可以产生一系列的按时间顺序索引的数据点。在时间序列中&#xff0c;数据具…

dp入门(二)

目录 45、跳跃计划 53、最大子数组和 55、跳跃游戏 62、不同路径 63、不同路径2 64、最小路径和 70、爬楼梯 72、编辑距离 84、柱形图中最大的矩形 85、最大矩形 4721、排队 45、跳跃计划 当前可移动距离尽可能多走&#xff0c;如果还没到终点&#xff0c;步数再加一。整体…

Spring Boot 入门

37) Boot 骨架项目 https://start.spring.io/pom.xml 38) Boot War项目 步骤1&#xff1a;创建模块&#xff0c;区别在于打包方式选择 war 步骤2&#xff1a;编写控制器 Controller public class MyController { ​RequestMapping("/hello")public String abc() …