flask-Blueprint蓝图
通俗解释:
蓝图就是把所有的路由都分解成一块一块的,再把这些块和app联系,怎么联系?→(在view中定义一个蓝图,蓝图其实就是原来所用的app,只不过是换了一个名字,定义完了之后,还要在__init__中注册,相当于通上电。然后就可以在view中写各种动作,即各种路由,这些动作与以前相比是基本不变的)
其实app的启动就像是一个插排,所以为了防止代码冗余杂乱,需要把app的启动放到一个python包里。
本篇文章实现的功能是:利用蓝图,把用户有关的用户中心、注册界面、登录界面、更新界面和退出界面展示出来。其中注册界面中可以删除和修改,并能显示出当前所注册的人数。页面的装饰部分用到模板继承
流程说明:新建项目后,新建一个app包,自动会生成一个__init__文件。
1.在app包中,分别新建goods、order、user这三个包,代表着不同功能。在templates文件夹中也分别创建goods、order、user这三个文件夹,用来存放各自的html。(本例中只简单实现了有关user的功能,所以templates中创建了user)
2.在__init__这个文件里定义一个函数
from flask import Flask
import settings # 导入配置文件
from app.user.app10_23_view import user_bp
def create_app():
app = Flask(__name__,template_folder='../templates',static_folder='../static')
app.config.from_object(settings) # 加载配置
app.register_blueprint(user_bp) # 搭建桥梁!!将蓝图对象绑定到app上 # 注册蓝图到app上 user_bp是对象 注册蓝图到app上是很关键的一步!!!
return app
其中 template_folder=‘…/templates’,static_folder=‘…/static’ 这样声明是因为:app包中的__init__和templates中的模板不是在同一级。解决方法可以是把templates和static等文件拖进app包里;
也可以像上面这样,在创建app的时候,声明一下,…/的意思是在上一级目录的某某文件夹中。
3.在app10_23中调用__init__中定义的函数
from flask import Flask
from app import create_app # 从包里导入这个函数
app = create_app() # 调用这个函数并得到返回值
if __name__ == '__main__':
app.run()
4.和用户有关的操作,会涉及到列表的增删改查。所以先在app包下的user包内创建一个model.py,在model.py中定义一个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
5.在app包中的user包中,新建app10_23_view.py,专门用来写视图的。
from flask import Blueprint, url_for, render_template, request, redirect
from app.user.model import User # 导入在model.py中定义的user类
user_bp = Blueprint('user', __name__) # bp是Blueprint的缩写,'user'是给蓝图起的名字!(这个名字很重要,后面反向解析路由的时候会用到)
users = [] # 列表保存的是一个一个的用户对象
@user_bp.route('/') # 在蓝图上注册路由
def user_center(): # 用户中心
print(url_for('user.register')) # 反向解析,用蓝图之后,一定要加上蓝图的名字再使用反向解析(一开始我没有加user. ,就会报错)
return render_template('user/app10_23_show.html', users=users) # render_template()是页面的渲染。此句代码会通过 render_template去找到user目录下的app10_23_show.html来装饰页面。
@user_bp.route('/register', methods=['GET', 'POST']) # 涉及到表单,必须注意methods要加上post这种方法! # 这是注册
def register():
if request.method == 'POST': # 如果就要往后台放数据,提交方法是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:
return render_template('user/app10_23_register.html', msg='用户名已存在') # 如果重名了,就返回一个 msg='用户名已存在'
user = User(username, password, phone) # 创建user对象
users.append(user) # 添加到用户列表
return redirect('/') # 重定向到主页
return render_template('user/app10_23_register.html') # 提交完数据之后,再进入app10_23_register.html的渲染界面
@user_bp.route('/login', methods=['GET', 'POST']) # 涉及到表单,必须注意methods
def login():
return '用户登录'
@user_bp.route('/del') # 删除主要是分为三步
def del_user():
# 获取你传递的username
username = request.args.get('username')
# 根据username找到列表中的user对象
for user in users:
if user.username == username:
# 删除user
users.remove(user)
return redirect('/') # 重定向到首页
else:
return '删除失败!'
@user_bp.route('/update', methods=['GET', 'POST'], endpoint='update') # 更新,涉及到数据提交到后台,所以method需要加上post;enpoint是相当于给这个路由起个名字,在url_for()路径反向解析时很方便。
def update_user():
if request.method == '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 == realname:
user.username = username
user.phone = phone
return '更改成功!'
else: # 也就是get请求
username = request.args.get('username')
for user in users:
if user.username == username:
return render_template('user/app10_23_update.html', user=user)
@user_bp.route('/longout', methods=['GET', 'POST']) # 涉及到表单,必须注意methods
def logout():
return '用户退出'
6.在view.py中涉及到的三个html分别是:app10_23_show.html、app10_23_register.html、app10_23_update.html。分别完成这三个html的代码部分:
(1)app10_23_show.html.在这个html中涉及到模板继承,也就是继承了app10_23_base.html,先给出base.py的代码:
<!DOCTYPE html> # base.py中的代码是固定装饰的基本框架,其他需要改动的部分去{%block...%}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{% block title %} 用户中心 {% endblock %}{#因为title是变化的,所以给它预留了一个block坑#}
</title>
<style>
#head{
height:50px;
background: bisque;
}
#head ul {
list-style: none; {#不让它的前边显示那个圆点#}
height: 50px;
}
#head ul li{
float: left;
width: 100px;
text-align: center;{#字体居中#}
font-size: 18px;
height: 50px;
line-height:50px;
}
#middle{
height:600px;
background-color: #86989B;
}
#foot{
height: 50px;
line-height: 50px;
background-color:darkred;
}
</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>
以下是app10_23_show.html的代码部分:
{% extends 'app10_23_base.html' %} {#意思是继承app10_23_base.html block和endblock是不区分先后顺序的#}
{% block middle %}
<h1>用户信息</h1>
<span>当前用户的人数是:{{ users | length }}</span>
<table border="1" cellspacing="0" width="60%" >
{% for user in users %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ user.username }}</td>
<td>{{ user.passwoed }}</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>
//定义删除的函数
function del(username){
// console.log(username)
//location 地址栏对象
location.href = '/del?username='+username {#点谁就要把谁的名字拼接到后边来#}
}
//定义修改的函数
function update(username){
// console.log(username)
//location 地址栏对象
location.href = '/update?username='+username {#点谁就要把谁的名字拼接到后边来#}
}
</script>
{% endblock %}
(2)app10_23_register.html的代码部分:
{% extends 'app10_23_base.html' %} {#意思是继承app10_23_base.html blockhe endblock是不区分先后顺序的#}
{% block title %}
用户注册
{% endblock %}
{% block middle %} {#middle的样式#}
<p style="color:red">{{ msg }}</p>
<form action="{{ url_for('user.register') }}" method="post"> {#这个地方写错了,一开始写的’user.app10_23_register‘,重定向的时候应该写路径,而不是文件名#}
<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 %}
(3)app10_23_update.html的代码部分:
{% extends 'app10_23_base.html' %}
{% block title %}
用户信息修改
{% endblock %}
{% block middle %}
<h1>用户信息更新</h1>
<form action="{{ url_for('user.update') }}" method="post">
<p><input type="hidden" name="realname" value="{{ user.username }}"></p>
<p><input type="text" name="username" placeholder="用户名" value="{{ user.username }}"></p>
<p><input type="password" name="password" placeholder="密码" value="{{ user.password }}" disabled></p>
<p><input type="number" name="phone" placeholder="手机号码" value="{{ user.phone }}"></p>
<p><input type="submit" value=用户注册"></p>
</form>
{% endblock %}
7.最后要补上setting.py配置文件
# 配置文件
ENV='development'
DEBUG=True