首先创建一个新项目
可以正常运行与访问
创建配置文件并添加配置。
将这里拆分到不同的文件中,让启动文件更加简洁。
创建一个apps包,导入配置模块,导入Flask,定义创建app函数,返回app对象。实例化的Flask对象做配置,定义模板位置和静态文件位置。添加app config配置,使用来自对象的方法,将配置模块导入到配置中
然后再来写我们的运行程序。导入创建 app函数,创建app,让app点run运行
我们将路由和视图函数写到views里面,这样启动文件就简洁了。我们将配置文件写到一个模块里面,这样创建好Flask对象之后,不用app.config往后堆很多配置,简洁很多。使用app点config点来自对象,将模块作为参数传入进去。
一个项目:比如分用户 商品 订单
一个项目分很多部分。我们不可能把所有的路由放到一个文件。
比如用户,就可以有
用户中心 /center
用户注册 /register
用户登录 /login
用户更新 /upgrade
一个用户部分就有很多路由。那么我们可以项目的一个部分就用一个蓝图,把路由划分成不同的部分。其实蓝图也是路由的另一种方式。
我们在apps下创建视图模块,里面写一个蓝图。蓝图里写了两个视图函数,
user_for('')调用register,如果有endpoint,返回的是endpoint的值,如果没有,返回的是函数的名,这是反向解析。就是给我个名我去找到路径,而不是给个路径我去找到函数名。正常的是给个路由,我给你找到函数名,现在反过来了,你给我函数名我给你找到路由,这就是url_for反向解析,
写完蓝图后导入并注册到app中
注册完了之后就命令行运行app程序并访问
一访问就报错了
因为原来我们是在app上写路由,现在我们用了蓝图了,多了一层,经过蓝图然后写的路由。所以url_for想要反向解析引用函数名,就需要在前面加上蓝图,指定是哪个蓝图下的函数名,然后我们再访问
这样就访问到了默认路由根了。
后端打印出 我们根据字符串反向解析出路径。包括在前端进行反向解析的时候,也要这么写,加上蓝图名称
我们这里沿用上面的结构做些修改。
我们将路由和视图函数写到views里面,这样启动文件就简洁了。我们将配置文件写到一个模块里面,这样创建好Flask对象之后,不用app.config往后堆很多配置,简洁很多。使用app点config点来自对象,将模块作为参数传入进去。
项目:比如分用户 商品 订单
一个项目分很多部分。我们不可能把所有的路由放到一个文件。
比如用户,就可以有
用户中心 /center
用户注册 /register
用户登录 /login
用户更新 /upgrade
一个用户部分就有很多路由。那么我们可以项目的一个部分就用一个蓝图,把路由划分成不同的部分。其实蓝图也是路由的另一种方式。
我们可以在apps下创建多个目录,用户目录放用户相关的,商品目录放商品相关,放的可以是蓝图等,比如view模块里面定义蓝图。
现在目录结构如下:
我们根据项目的不同的部分划分。这里创建了三个包,我们现在要写跟用户相关的,所以我们写蓝图在user下面的view模块写蓝图。app,配置还有init文件已经按上面那个写好了。现在只需要把蓝图重新写一下。
程序:
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.register_blueprint(user_bp) print(app.url_map) return app
from flask import Blueprint user_bp=Blueprint('user',__name__) @user_bp.route("/") def user_center(): return '用户中心' @user_bp.route('/register',methods=['GET','POST']) def register(): return '用户注册' @user_bp.route('/login',methods=['GET','POST']) def login(): return '用户登录' @user_bp.route('/logout',methods=['GET','POST']) def logout(): return '用户注册'
用户下写的蓝图:
现在我们写了四个路由了。这四个路由绑定在蓝图上的,也就是绑定在user蓝图上的。蓝图需要注册到app中,让蓝图和app产生联系。
在apps下的init里面,导入蓝图,在app对象里面注册我们创建的蓝图,我们可以用url_map查看app里的路由,可以看到我们写的四个路由,已经生效了。
我们访问一下看效果:
我们需要定义类,用于与数据库交互用的。在用户目录下创建model模块。写入到这个模块中
现在我们需要写模板了,模板目录创建子目录user,跟用户相关的模板就放到这个目录中。比如我们先创建三个文件,登录,注册和展示用的页面。因为这些页面都有公共的部分。所以我们需要将公共的部分分出来。我们在templates下创建base页面。
母版的写法:
base母版页面的标题也是可能改的,设置成block,默认是用户中心
我们还需要预留我们的css和js。所以母版中再设置css和js块。然后我们创建三个div,分为header center footer.然后定义三者的样式
刚刚的有点问题,右击模板目录,将目录标记为模板目录,使用jinja2语言。这样下面的block就识别出来了
"en"> "UTF-8">{% block title %} 用户中心{% endblock %} {% block mycss %}{% endblock %}"middle"> {% block middle %} {% endblock %}"foot">{% block myjs %}{% endblock %}
母版展示效果如下
我们要写注册页面。我们需要继承母版。修改标题,
{% extends 'base.html' %} {% block title %} 用户注册 {% endblock %} {% block middle %}{% endblock %}
将
我们写好前端页面之后。写后端,让注册视图返回这个模板文件看看效果。因为模板目录能找到,文件在子目录中,所以用相对路径就可以找到文件。
效果如下:
我们在创建flask对象的时候,设置了模板文件位置,静态文件位置了。所以flask能找到模板目录。如果在创建flask对象的时候没有设置传参那么就只能把模板目录放到apps下,和init文件同级目录,因为,创建flask对象的时候,内部有默认设置找到创建对象同级目录下的templates目录作为模板目录。同理,我们也要设置一下静态文件目录、。因为我们要将apps和模板目录独立开来,不放到apps下。
接下来我们写post提交数据。点击注册,然后跳转到用户中页面
目前我们的model这个类,可以封装用户的用户名,密码。打印对象会显示用户名。用户数据封装在init方法下面。
用户数据暂时先保存到一个列表中。有一个就追加一个到列表中。将用户类导入进来,创建用户对象,将用户数据封装进对象中。注册后是将用户对象追加到用户对象列表里面了。
然后看一下用户注册的逻辑。
查看效果
给我们的注册页面添加上错误显示
{{ msg }}
目前缺少很多校验
成功跳转到用户中心页面
接下来写用户中心的页面,用户中心页面是展示用的,那么我们也就返回一个展示模板,因为需要展示用户的,那就将users对象列表传进去。传的方法是变量等于用户对象列表。
用户中心展示页面,我们得知道需要展示哪些新喜,标题,当前用户人数等。然后每个人的信息。这里就做个表格,将后端传进来的用户对象列表做循环。然后点取值
如下,我们进入注册页面,注册后跳转到用户信息页面。这样就将信息都展示出来了。用户信息需要修改和删除按钮、。loop.index应该是循环的索引
我们应当还需要添加。一般数据展示页面,需要增改删按钮,查已经实现了、。
现在我们需要删除
删除一条数据,一个用户。我们需要准确的知道是删除那条数据。点击删除按钮或者是链接,就发送请求,让它请求/del删除路径。这样让它找到删除用户操作的删除视图函数。这个功能的实现需要js来配合实现。前端上是添加一个js点击事件,
下面看下如何添加js点击事件。
在删除a标签上添加点击事件函数传一个字符串用户的名字。这里是根据用户名去删除。下面就添加js代码块。定义js语句。定义js函数,函数是点击事件中调用的函数。function 函数名小括号接收点击事件传给函数的参数,然后花括号定义点击事件发生后的行为。这里暂时是打印在控制台。js函数的调用时,给href链接加上Javascript冒号分号,然后后面接事件类型,事件是点击事件=双引号,双引号里面可以放函数的调用。调用的括号里面可以放给函数的传参。传参这里是传的字符串。传的是一个用户名字这个变量。这样,点击谁,就传参是谁,下面的函数可以定位到对那条数据做删除操作。
点击之后成功打印,说明没有问题。后面再改成删除的行动
删除的逻辑应该是如下:
现在当我们点击删除a链接时,不是打印输出在控制台了。是要发送一个请求。我们这里注释掉a标签的请求,使用调用js函数的方式来做请求。做的是个get请求。也就是删除按钮是个点击事件。当点击这个标签时,调用del函数并传参用户名字给函数。js代码块中定义的del函数接收到传参,知道是哪个用户要被删除,函数要做的动作是想/del路径发送get请求,并拼接上用户名,因为这里是根据用户名来删除,将用户名作为get请求的参数传递给后端视图函数。后端视图函数接收到传参后就可以对该数据做操作了。js中location.href等于一个地址,可以使得函数执行时,对该地址发送一个get请求。拼接键值对用问号,键自己指定,值是js函数传参接收过来的用户名。键值对等号拼接
删除逻辑如下:前端想del发送一个请求,并将用户传到后端了,视图函数中获取get请求中的数据,然后对用户做判断。循环我的用户列表.如果用户对象列表的每个用户名字和前端传递过了的名字相等,那么就将用户从用户对象列表中删除,然后重定向到用户中心页面。如果循环结束之后发现没有匹配到用户,也就没走到重定向这一步,我们可以else否则给它返回一个删除失败。
这下我们点击删除
发现删除成功
注册模板中我们写action地址,我们要访问的是蓝图user下的/register这个路由,但是这个路由也是可能会被修改的。如果被修改了,前端action地址就访问不到了,所以前端不能写死了,我们应该用动态的反向解析的方法去获取到路由地址,从而正确访问到该路由。{{ url_for('user.register') }} 就是通过字符串,能反向解析出路由地址,然后访问路由从而实现向这条路由发起请求。正常来说我们是通过路径找到函数,而我们这里就是通过函数名或endpoint去找到路径,这就是反向解析
接下来我们要做修改的程序
前端设计:
下面看下展示效果
接下来就是写/update路由也就是修改页面的post请求了。
修改逻辑
重定向到用户展示页面效果
class User: def __init__(self, username, password, phone=None): self.username = username self.password = password www.gsm-guard.net = phone def __str__(self): return self.username
from flask import Blueprint,request, render_template, redirect from apps.user.model import User user_bp=Blueprint('user',__name__) # 列表保存的是一个一个的用户对象 users = [] @user_bp.route("/") def user_center(): return render_template('user/show.html',users=users) @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=['POST', 'GET'], endpoint='update') 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 www.gsm-guard.net = 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) @user_bp.route('/register',methods=['GET','POST']) def register(): if request.method=='POST': # 获取post提交的数据 print(request.form) print(request.form.get('username')) username = request.form.get('username') password = request.form.get('password') phone = request.form.get('phone') repassword = request.form.get('repassword') if password == repassword: # 用户名唯一 for user in users: if user.username == username: return render_template('user/register.html', msg='用户名已存在') # 创建user对象 user = User(username, password, phone) # 添加到用户列表 users.append(user) return redirect('/') 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 '用户注册'
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.register_blueprint(user_bp) return app
{% extends 'base.html' %} {% block title %} 用户注册 {% endblock %} {% block middle %}{% endblock %}"color: red">{{ msg }}
{% extends 'base.html' %} {% block middle %}用户信息
当前用户人数是:{{ users |length }} 人
{{ loop.index }} | {{ user.username }} | {{ user.password }} | {{ www.gsm-guard.net }} | "javascript:;" onclick="update('{{ user.username }}')" >修改 "javascript:;" onclick="del('{{ user.username }}')">删除 |
{% extends 'base.html' %} {% block title %} 用户信息修改 {% endblock %} {% block middle %}{% endblock %}用户信息更新
"en"> "UTF-8">{% block title %} 用户中心{% endblock %} {% block mycss %}{% endblock %}"middle"> {% block middle %} {% endblock %}"foot">{% block myjs %}{% endblock %}
from apps import create_app app=create_app() if __name__ == '__main__': www.gsm-guard.net()
ENV="development" DEBUG=True