【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__)
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 %}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岳涛@心馨电脑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值