1、后端
服务器+wsgi+框架程序,flask是框架程序
2、前端
手机APP、浏览器、程序(爬虫)、urllib、urllib2、ajax
3、框架的核心
实现路由和视图(业务逻辑处理);
4、优势
dingo是重量级框架,提供了很多工具和组件,对后期扩展不友好;
5、flask的核心
werkzeug和jinja2(jinja2可以换)
6、flask扩展包:
Flask-SQLalchemy:操作数据库;Flask-migrate:管理迁移数据库;Flask-Mail:邮件;Flask-WTF:表单;Flask-script:插入脚本;Flask-Login:认证用户状态;Flask-RESTful:开发REST API的工具;Flask-Bootstrap:集成前端Twitter Bootstrap框架;Flask-Moment:本地化日期和时间;
7、虚拟环境:
cd ~/ :切换到家目录:ls -l: ls -a:cd .virtualenv: ls: 所有的虚拟环境cd flask_py2: 切换至某个虚拟环境cd bin:可执行的二进制文件;cd ..:返回上级目录;cd lib:所有的安装包;cd site-packages:可以修改第三方包中的源文件pip list :查看当前虚拟环境中安装了哪些包mkvirtualenv shop -p python3:创建虚拟环境shop,并指定python版本安装python包时加sudo,安装到系统环境中,并非虚拟环境中;
二、app对象的初始化和配置:1、对象的初始化
__name__表示当前文件名字,如果这个文件为启动文件的话,__name__为 __main__app=Flask(__name__)表示以当前文件所在的目录为根目录,flask以这个模块所在的目录为根目录,默认以根目录下的static作为静态目录,以根目录下的templates作为模板目录,如果flask传的参数没有被找到,比如app=Flask('idbbkdsbkjabs'),flask会以当前文件为根目录Flask()的初始化参数:
import_name: static_url_path: 访问静态资源的默认名称,把在浏览器中访问的static换掉(120.0.0.1:5000/static/index.html换成120.0.0.1:5000/static1/index.html)static_folder: 静态文件的目录,默认‘static’template_folder: 模板文件的目录,默认‘templates’
2、app.run():
为简易的测试服务器
app.run(host='0.0.0.0',port=5000) # 既可以使用本地ip地址,又可以使用127.0.0.1访问,可以传debug
3、配置文件:
存值:
(1)app.config.from_pyfile(文件名) #指定文件名字,以当前根目录下的文件名查找(2)app.config.from_object(类名) # 从对象的方式导入,配置文件封装成类(3)app.config['DEBUG']=True # 指直接操作config的字典对象
取值
(1)app.config.get('')(2)app.config[''](3)current_app.config['']
三、视图函数的路由:1、视图函数的路由规则:
app.url_map:可以查看整个flask的路由信息
返回Map([Rule'/'(HEAD,OPTIONS,GET)->index,...]) 路由 请求方式 视图函数名称
如果定义了两个相同的视图函数,路由也相同,则第一个会把第二个干掉一个视图函数可以添加多个路由url_for:通过视图函数名称找到路由,返回的是路由地址,即url
2、url中的传参:
(1)转换器(动态路由):127.0.0.1:5000/user/123
@apiBP.route('/user/
(2)自定义转换器:
定义自己的转换器:
class ReqexConverter(Werkzeuq.rounting.baseConverter): def __init__(self,url_map,regex): # 调用父类的初始化方法 super().init() # 将自己使用的正则表达式的参数保存到对象的属性中, flask回去使用这个属性来进行路由的正则匹配 self.regex=regex def to_python(self,value): ''' 对regex值做更复杂的操作,传的值经过校验是正常的,则返回return中的值 路径中的值转换到python程序中 ''' return 处理过后的数据,即最终的mobile_id def to_url(self,value): return '15812345678'
将自定义的转换器添加到flask应用中
app.url_map.converters['re']=ReqexConverter
案例
@apiBP.route('/user/
1、获取参数:
request.form:可以提取请求体中表单格式的数据:city=xxx&age=xxx&name=xxx,form表单中的参数;request.data:请求体中不是表单格式的数据,如json传过来的字符串;request.files['文件字段名']:返回的是文件对象
f=request.files['the_file']f.save('/download/test001.txt') # flask中文件特有的方法f.read()f.write()
五、abort函数、自定义错误,视图函数返回值:1、abort函数的使用:
(1)视图函数中,可以使用abort(),终止视图函数执行,并将错误信息返回到前端。
可以传递状态码信息,必须是标准的http状态码:abort(404);传递详细信息(需要是Respoese对象):abort(Respoese());
2、自定义异常处理:
@app.errorhandler(404)def error(e): return '您请求的页面不存在了,请确认后再次访问!%s'%e
3、返回值信息:
(1)可以返回一个元组,这样的元组必须是 (response, status, headers) 的形式,且至少包含一个元素。 status 值会覆盖状态代码, headers 可以是一个列表或字典,作为额外的消息标头值。如果是列表,[(‘响应头1的名称’,‘响应头1的值’),(‘响应头2的名称’,‘响应头2的值’)];
(2)使用make_response
resp = make_response('响应体')resp.headers[“sample”] = “value”resp.status = “404 not found”
(3)返回json
@apiBP.route('/index')def index(): data={ 'name':'wmz', 'age':18 } # json_str=json.dumps(data) # return json_str,200,{'Content-Type':'application/json'} # jsonify将字典转换为json格式数据,并修改响应头为json return jsonify(data) return jsonify(city='shanghai',age=18)
六、cookie和session:1、设置cookie
resp = make_response('响应体')
默认有效期是临时cookies,浏览器关闭即失效,max_age为有效期,单位为秒
(1)resp.set_cookies('Itcast','python',max_age=3600)(2)resp.headers['Set-cookies']='Itcast=python,Max-Age=3600'
2、操作cookies
获取cookies:request.cookies.get('Itcast')删除cookies:设置有效期,使有效期过期
resp = make_response('删除cookies')resp.delete_cookie('Itcast')
3、设置session数据
flask中session需要用到的秘钥字段
app.config['SECRET_KEY']='HAHAHHAHHAHAH'session['name']='python'session['age']=18
后端产生sessionId传给浏览器,浏览器下次再访问时,cookie中携带sessionId;flask把session数据保存在了cookie中,没有保存在后端服务器中;可以把session数据保存在数据库、redis、文件、程序内存中(定义一个全局变量)。
4、操作session数据
name=session.get['name']
七、flask上下文和钩子:1、上下文
(1)请求上下文(request context),request和session都属于请求上下文对象,处理多个请求的情况;
request={'线程A':{'form':{'name':'zhangsan'},args:{}},'线程B':{'form':{'name':'lisi'},args:{}}}
(2)应用上下文(application context),处理有多个应用的情况;
current_app和g都属于应用上下文对象;current_app:表示当前运行程序文件的程序实例;g:处理请求时,用于临时存储的对象,每次请求都会重设这个变量。一次请求之内,需要调用多个函数,就可以用g变量来定义变量。
@apiBP.route('/index')def index(): data={ 'name':'wmz', 'age':18 } g.username='zhangsan' say_hello()def say_hello(): username=g.username
2、钩子
flask支持四种钩子:可以使用request方式进行处理:
before_first_request:在处理第一个请求前运行;
@app.before_first_requestdef handle_before_first_request(): print('在第一次请求前运行')
before_request:在每次请求前运行;
after_request(response):如果没有未处理的异常抛出,在每次请求后运行(前提是视图函数没有出现异常,必须有返回值);
teardown_request(response):在每次请求后运行,即使有未处理的异常抛出(不管视图函数是否有异常,都会执行,必须有返回值)。
3、flask-script
from flask-script import Manager # 启动命令的管理类manager=Manager(app) #创建manager的管理对象manager.run() # 启动flask,启动了之后,可以用命令执行
八、模板:1、模板和自定义过滤器
return render_template('index.html',name='python')
2、模板中可以进行运算
{{myList[0]+myList[1]}}
3、默认的过滤器
(1)字符串过滤器:
safe:禁用转义; {{ 'hello' | safe }} {{ 'hello' | capitalize }} {{ 'HELLO' | lower }} {{ 'hello' | upper }} {{ 'hello' | title }} {{ ' hello world ' | trim }} {{ 'olleh' | reverse }} {{ '%s is %d' | format('name',17) }} {{ 'hello' | striptags }} {{ “ hello world “ | trim | upper }}
(2)列表过滤器
first:取第一个元素 {{ [1,2,3,4,5,6] | first }} {{ [1,2,3,4,5,6] | last }} {{ [1,2,3,4,5,6] | length }} {{ [1,2,3,4,5,6] | sum }} {{ [6,2,3,1,5,4] | sort }}
4、自定义过滤器
(1)通过 add_template_filter (过滤器函数, 模板中使用的过滤器名字)
def filter_double_sort(ls): return ls[::2]app.add_template_filter(filter_double_sort,'double_2')
(2)通过装饰器 app.template_filter (模板中使用的装饰器名字)
@app.template_filter('db3')def filter_double_sort(ls): return ls[::-3]
5、处理表单
#设置csrf_token{{ form.csrf_token() }}{{ form.user_name.label }} {{form.user_name}} {{msg}}
6、宏
(1)模板中多次使用的内容可以被定义为宏;
不带参数:
{% macro input() %} {% endmacro %}使用:{{ input() }}
带参数:
{% macro input2(type,value,size='30') %} {% endmacro %}使用:{{ input('password','name') }}
(2)外部引用:文件名可以自定义macro.html;
{% macro input() %} {% endmacro %}
在其它模板文件中先导入,再调用{% import 'macro.html' as func %}{{func.input()}}
7、模板的继承
父模板:
{% block top %}顶部菜单 {% endblock top %} {% block content %} {% endblock content %} {% block bottom %}底部 {% endblock bottom %}
子模板:
{% extends 'base.html' %} {% block content %} 需要填充的内容 {% endblock content %}
模板继承使用时注意点:
不支持多继承。为了便于阅读,在子模板中使用extends时,尽量写在模板的第一行。不能在一个模板文件中定义多个相同名字的block标签。当在页面中使用多个block标签时,建议给结束标签起个名字,当多个block嵌套时,阅读性更好。 九、数据库扩展包:
1、创建外键:
class User(UserMixin,base): """ 用户信息表 """ __tablename__ = 'sp_user' userid = Column(Integer, primary_key=True) user_name = Column(String(24),unique=True, nullable=False) # 用户名称 addresses=relationship('Address',backref='user')
class Address(base): """ 收货地址 """ __tablename__ = 'sp_address' addressId=Column(Integer, primary_key=True) userId=Column(Integer, ForeignKey('sp_user.userid')) # 创建人id provinceId=Column(Integer, nullable=False) # 省ID
2、查询数据
方法1:通过SQLA...方式查询db.session.query(Role).all()方法2:通过flask-sqla...方式查询Role.query.all()
3、条件查询
Role.query.filter(Role.name='管理员').all()Role.query.filter_by(name='管理员').all()
4、关联查询
user=User.query.get(1)user.Address # 可以返回userID等于1的所有地址信息address=Address.query.get(1)address.user #返回addressID等于1所属的人员信息
5、让查询出来的,在输出信息中的数据显示更直观
class User(UserMixin,base): """ 用户信息表 """ __tablename__ = 'sp_user' userid = Column(Integer, primary_key=True) user_name = Column(String(24),unique=True, nullable=False) # 用户名称 addresses=relationship('Address',backref='user') def __repr__(self): return 'User object name=%s' %self.user_name
6、更新操作
User.query_by(user_name ='zhou').update({'addresses':'上海'})
十、数据库迁移包,邮件扩展包:pip install flask-migrate#coding=utf-8from flask import Flaskfrom flask_sqlalchemy import SQLAlchemyfrom flask_migrate import Migrate,MigrateCommandfrom flask_script import Shell,Managerapp = Flask(__name__)manager = Manager(app)app.config['SQLALCHEMY_DATAbase_URI'] = 'mysql://root:mysql@127.0.0.1:3306/Flask_test'app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = Trueapp.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = Truedb = SQLAlchemy(app)#第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例migrate = Migrate(app,db) #manager是Flask-script的实例,这条语句在flask-script中添加一个db命令manager.add_command('db',MigrateCommand)#定义模型Roleclass Role(db.Model): # 定义表名 __tablename__ = 'roles' # 定义列对象 id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) def __repr__(self): return 'Role:'.format(self.name)#定义用户class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, index=True) def __repr__(self): return 'User:'.format(self.username)if __name__ == '__main__': manager.run()
创建migrations文件夹,所有迁移文件都放在里面。
python database.py db init
创建自动迁移脚本
python database.py db migrate -m 'initial migration'
更新数据库
python database.py db upgrade
查看历史版本的具体版本
python database.py db history
复制具体版本号执行回退
python database.py db downgrade 版本号
十一、蓝图:定义蓝图时,没有默认静态文件目录,需要手动定义,template_folder='templates';模板文件的查找顺序: 先去定义app时定义的模板目录查,定义app时默认的模板目录为根目录下的templates如果没有找到,再去定义蓝图的时候定义的模板目录里找。 十二、flask部署:
Gunicorn(绿色独角兽)是一个Python WSGI的HTTP服务器;WSGI:全称是Web Server Gateway Interface(web服务器网关接口),它是一种规范,它是web服务器和web应用程序之间的接口。它的作用就像是桥梁,连接在web服务器和web应用框架之间;uwsgi:是一种传输协议,用于定义传输信息的类型;uWSGI:是实现了uwsgi协议WSGI的web服务器。
gunicorn -w 4 -b 127.0.0.1:5000 -D --access-logfile ./ Logs/ Log main:app-D:以后台守护进程进行--access-logfile ./ Logs/ Log:日志文件(访问的历史记录)nginx(会保证轮着进行转发,访问每个服务的机会均等)
使用nginx部署,配置nginx.conf文件。