1.加载应用程序配置
加载应用程序配置有三种方式:
1/从配置对象中加载配置信息from_object
2/从配置文件中加载配置信息
3/从环境变量中加载配置信息
重点掌握第1种,在工作中,我们的项目在启动的时候,需要预先设置一些配置信息,为了方便管理,便于维护,我们将所有的配置信息,封装在一个类中,然后再进行使用,下面是代码的实现过程,大家可以看一下:
1# 1.导入Flask类
2from flask import Flask
3# 2.创建Flask对象接收一个参数__name__,它会指向程序所有的包
4app = Flask(__name__)
5# 配置对象,里面定义需要给APP添加的一系列配置
6class Config(object):
7 DEBUG = True
8
9# 从配置对象中加载配置
10app.config.from_object(Config)
11
12# 3.装饰器的作用是将路由映射到视图函数index
13@app.route("/")
14def index():
15 return 'Hello World'
16
17# 4.Flask应用程序实例的run方法,启动WEB服务器
18if __name__ == '__main__':
19 app.run()
提示: 运行测试,在修改代码之后直接保存,会自动重启服务器 通过:app.config.get('DEBUG') 可以获取到配置的信息
2.路由定义
2.1指定请求方式
methods
,它有很多参数,但是我们需要掌握最常用的两个
1.GET
是请求,浏览器第一次请求的时候是此get请求
2.POST
是提交,这种方式更加的安全,所有的信息是打包进行提交的,我们在防止csrf攻击的时候,就是在post请求的时候,验证csrf_token
具体使用:
1@app.route('/demo',methods=['GET','POST'])
2def demo():
3 # 直接从请求中取到请求方式进行返回
4 return request.method
2.2重定向
redirect('路径')
路径既可以是外链地址,又可以是视图函数的地址,是字符串的形式.(tip:在使用外链地址的时候,记得在前面加http://)
url_for('函数名',key=value)
是反解析,通过视图函数的名称,返回一个地址,经常配合redirect使用
1@app.route('/demo1/<int:user_id>')
2def demo1(user_id):
3 return 'hello %d' % user_id
4
5# 重定向
6@app.route('/demo5')
7def demo5():
8 # 使用url_for生成指定视图函数所对应的url
9 return redirect(url_for('demo1',user_id=100))
2.3返回json
response=jsonify(dict)
json数据其实是一个字符串,里面是一个字典,如:'{"name":"zhangsan","age":"10"}'
,要注意的是,json对象的属性名称和字符串必须由双引号引起来,否则会报错.
json和dict相互转换:
1# 使用之前需要导入一个类
2from flask import json
3# 1.json转换成字典
4dict = json.loads(json)
5# 2.字典转换成json
6json = json.dumps(dict)
2.4自定义状态码
response=make_response()
自定义状态码:
response.status = 200
自定义响应头:
response.headers["Content-Type"]="application/json"
自定义cookie:
response.set_cookie("name","aaa")
3.Request请求
args
是请求信息,地址栏数据 ,问号后面,如www.baidu.com?key=value&key=value
data
是json/xml等,非表单post提交的请求
form
表单post请求提交的
cookies
是存储在浏览器里面的信息
属性 | 说明 | 类型 |
---|---|---|
data | 记录请求的数据,并转换为字符串,非表单数据 | * |
args | 记录请求中的查询参数 | MultiDict |
form | 记录请求中的表单数据 | MultiDict |
cookies | 记录请求中的cookie信息 | Dict |
4.请求钩子
请求钩子有四种:我们重点掌握的只有两种:
before_request
在每次请求前执行,在该装饰函数中,一旦return,视图函数不再执行
after_request
如果没有抛出错误,每次请求后都执行(在执行完视图函数之后会调用,并且会把视图函数所生成的响应传入,可以在此方法中对响应做最后一步统一的处理)
5.状态保持
5.1cookie
cookie就是网站为了辨别用户的身份,进行会话跟踪而存储在用户本地的数据(通常是经过加密处理的),因为浏览器请求是无状态的,需要cookie才能在下次访问的时候知道上次做了什么,要不然每一次的刷新页面就是一次新的请求,什么记录都没有,好像我们从来没有来过一样,用户体验贼差,有了cookie就知道了用户浏览的状态,比如是否登陆过,之前看过写什么之类的.
这里有一个名词:同源策略,简单的来说,就是不同的网站之间的cookies不能共享
在运用的时候,代码如下:
1requestfrom flask import Flask,make_response,request
2app = Flask(__name__)
3# 设置cookies值
4@app.route('/set_cookie')
5def set_cookie():
6 response = make_response("set cookie")
7 response.set_cookie("name","xiaoyan",10) #10秒的有效期
8 return response
9# 获取cookie值
10@app.route('/get_cookie')
11def get_cookie():
12 # 获取cookie的时候是可以根据cookie的键名来获取cookie值的
13 # name = request.cookies["name"]但是这样错误的时候程序会崩掉,还是用get友好一点
14 # 可以根据cookie的内容来推荐商品信息
15 name = request.cookies.get("name")
16 return "获取到cookie,name is %s" % name
17
18if __name__ == '__main__':
19 app.run(debug=True)
5.2session
session
是保存在服务器的,对于敏感,重要的信息,建议存储在服务器端,比如用户名,余额等等.
cookie中只保存sessionID,在浏览器发起请求的时候,会连带着cookie,将sessionID一起发送给服务器,服务器根据sessionID提取session的值,每一个用户想服务器请求的时候,都会给其开辟对应的空间保存session信息.
在使用session
的时候一定要设置秘钥
1from flask import Flask,session
2app = Flask(__name__)
3# 设置秘钥
4app.config["SECRET_KEY"] = "dfdfdfd"
5# 设置session
6@app.route('/set_session/<path:name>') # path是字符串
7def set_session(name):
8 session["name"]=name
9 session["age"]="13"
10 return "set session"
11# 获取session的内容
12@app.route('get_session')
13def get_session():
14 name = session.get('name')
15 age = session.get("age")
16 return "name is %s,age is %s"% (name,age)
17if __name__ = '__main__':
18 app.run(debug=True)
session的存储依赖于cookie,在cookie保存的session编号session编号生成,需要进行加密,所以需要设置secret_key secret_key的作用参考:https://segmentfault.com/q/1010000007295395
6.上下文
上下文:相当于一个容器,保存了Flask程序运行过程中的一些信息
有请求上下文和应用上下文,重点掌握请求上下文
request
封装了HTTP请求的内容,针对的是HTTP请求
如user = request.args.get('user')
获取的是get请求的参数
session
用来记录请求会话中的信息,针对的是用户信息
如session['name'] = user.id
可以记录用户信息,
还可以通过session.get('name')
7.模板
7.1自定义过滤器
有两种形式,一种是先定义函数,再添加到过滤器列表中,另一种是装饰器的形式.重点掌握第一种.
1# 先定义一个函数
2def do_listreverse(li):
3 # 通过原列表创建一个新列表
4 temp_li = list(li)
5 # 将新列表进行反转
6 temp_li.reverse()
7 return temp_li
8# 第一个参数是上面定义的函数名,
9# 第二个参数是过滤器的名字
10app.add_template_filter(do_listreverse,'lireverse')
7.2模板中html代码
有宏/继承/包含
我们需要重点掌握的就是继承:继承指的是将公共部分我们抽取到父模板中,供子类使用的形式
父模板(base.html)中使用多个block
组成
1{% block top %}
2 顶部菜单
3{% endblock top %}
4
5{% block content %}
6 正文内容
7{% endblock content %}
8
9{% block bottom %}
10 底部
11{% endblock bottom %}
子模板在使用的时候先继承
1{% extends 'base.html' %}
2{% block content %}
3 子模板自己的内容
4{% endblock content%}
注意:在父模板中时正常的html页面,但是在子模板中直接写extends和block,不需要再写head标签,body标签这些了.
7.3模板中特殊变量函数
重点掌握的有两个
7.3.1request
就是flask中代表当前请求的request对象:
1{{ request.url }}
2输出:http://127.0.0.1
7.3.2url_for()
url_for 会根据传入的路由器函数名,返回该路由对应的URL,在模板中始终使用url_for()就可以安全的修改路由绑定的URL,则不必担心模板中渲染出错的连接
1{{ url_for('home) }}
2/
8.数据库
8.1Flask中使用数据库
8.1.1Flask-SQLAlchemy
SQLAlchemy是对数据库的抽象,让我们不用直接和SQL语句打交道,而是通过python对象来操作数据库,在舍弃一些性能开销的同时,换来的是开发效率的较大提升.是一个关系型数据库的框架,它提供了高层的ORM和底层的原生数据库操作.
8.1.2ORM类
类名称 | 类属性 | 类的对象 |
---|---|---|
数据库表名 | 数据库的字段 | 数据库表中的一行一行的数据 |
8.2一对多的关系
1/我们在定义模型的时候要继承的类是db.Model
2/添加外键的时候要添加在多方
3/添加关系的时候添加在一方
1class Role(db.Model):
2 ...
3 # 关键代码
4 添加关系
5 us = db.relationship('User',backref='role',lazy='dynamic')
6 ...
7class User(db.Model):
8 ...
9 # 添加外键
10 role_id = db.Column(db.Integer,db.ForeignKey('roles.id'))
其中relationship描述了Role和User的关系
第一个参数为对应参照的类"User"
第二个参数backref为类User,反向引用属性,即给多方指定内容访问一方
第三个参数lazy决定了什么时候SQLAlchemy从数据库中加载数据
动态(dynamic):这样关联对象会在被使用的时候再进行加载,并且在返回前进行过滤,如果返回的对象数很多,或者未来会变得很多,那最好采用这种方式
第四个参数secondary:指定多对多关系中关系表的名字
8.3数据的增删改
增加:
db.session.add()
db.session.add_all()
删除:
db.session.delete()
修改:
user.name = xiaoyan
提交:
db.session.commit()
回滚:
db.session.rollback()
8.4数据库的查询
模型类.query.过滤器.执行器
12条语句:
1/查询所有用户数据:
User.query.all()
2/查询有多少个用户:
User.query.count()
3/查询第一个用户
User.query.all()[0]
4/查询id为4的用户(3种方式)
User.query.get(4)
User.query.filter_by(id=4).fitst()
User.query.filter(User.id==4).first()
5/查询名字结尾字符为g的素哟有数据[开始/包含]
User.query.filter(User.name.endswith('g')).all()
User.query.filter(User.name.startswith('g')).all()
User.query.filter(User.name.contains('g')).all()
6/查询名字不等于wang的所有数据[2种方式]
User.query.filter(User.name!='wang').all()
from sqlalchemy import not_
User.query.filter(not_(User.name=='wang')).all
7/查询名字和邮箱都以li开头的所有数据[2种方式]
User.query.filter(User.name.startswith('li'),User.email.startswith('li')).all()
from sqlalchemy import and_
User.query.filter(and_(User.name.startswith('li'),User.email.startswith('li'))).all()
8/查询password是123456或者email以itheima.com
结尾的所有数据
from sqlalchemy import or_
User.query.filter(or_(User.password=='123456',User.email.endswith('itheima.com'))).all()
9/查询id为[1,3,5,7,9]的用户列表
User.query.filter(User.id.in_([1,3,5,7,9])).all()
10/查询name为liu的角色数据
user = User.query.filter(User.name=='liu').first()
role = Role.query.filter(Role.id==user.role_id).first()
11/查询所有用户数据,并以邮箱排序
User.query.order_by(User.email).all()
升序
User.query.order_by(User.email.desc()).all()
降序
12/每页3个,查询第2页的数据
paginate = User.query.paginate(page,per_page,Error_out)
paginate = User.query.paginate(2,3,False)
page
哪一页
per_page
每页多少条数据
Error_out
False查不到不报错
8.5数据库的迁移
数据库的迁移配合Flask_script使用
命令:
创建文件夹(此过程,只执行一次):
python xxx.py db init
生成指定版本迁移文件(每次改变的时候都需要执行):
python xxx.py db migrate -m 'sss'
升级或者降级:
python xxx.py db upgrade/downgrade[version]
查看最新/当前/历史版本:
python xxxx.py db show/current/history
8.6蓝图
将项目模块化的工具:
特点:
1/有自己的静态文件,模板文件
2/如果有静态文件,可以配置url_prefix去访问当前蓝图目录下的静态文件
3/蓝图本质上实现的原理(从源代码中看)
使用步骤:
1/创建蓝图对象(Blueprint)
admin = Blueprint('admin',__name__)
2/使用蓝图装饰函数
1@admin.route('/')
2def admin_home():
3 return 'admin_home'
3/将蓝图注册到app中(register_blueprint)
app.register_blueprint(admin,url_prefix='/admin')
优质文章推荐: