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,安装到系统环境中,并非虚拟环境中;
1、对象的初始化
__name__
表示当前文件名字,如果这个文件为启动文件的话,__name__
为 __main__
app=Flask(__name__)
表示以当前文件所在的目录为根目录,flask
以这个模块所在的目录为根目录,默认以根目录下的static
作为静态目录,以根目录下的templates
作为模板目录,如果flask
传的参数没有被找到,比如app=Flask('idbbkdsbkjabs')
,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
:通过视图函数名称找到路由,返回的是路由地址,即url2、url中的传参:
(1)转换器(动态路由):127.0.0.1:5000/user/123
@apiBP.route('/user/' , methods=['POST'])
def login(user_id):
""" 用户登录 """
print(user_id)
默认的类型:int/float/path(和默认的相似,但也接受斜线),不加转换器类型的话,默认为字符串
(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'
app.url_map.converters['re']=ReqexConverter
@apiBP.route('/user/1[34578]\d{9}'):mobile_id>', methods=['POST'])
def login(mobile_id):
""" 用户登录 """
print(mobile_id)
@apiBP.route('/index', methods=['POST'])
def login():
""" 用户登录 """
url=url_for('send_sms',mobile='18611111111')
# 相当于/send/15812345678
print(mobile_id)
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()
1、abort函数的使用:
(1)视图函数中,可以使用abort(),终止视图函数执行,并将错误信息返回到前端。
abort(404)
;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)
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
;session
数据保存在了cookie
中,没有保存在后端服务器中;session
数据保存在数据库、redis
、文件、程序内存中(定义一个全局变量)。4、操作session数据
name=session.get['name']
1、上下文
(1)请求上下文(request context
),reques
t和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_request
def 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:禁用转义;
<p>{{ 'hello' | safe }}</p>
capitalize:把变量值的首字母转成大写,其余字母转小写;
<p>{{ 'hello' | capitalize }}</p>
lower:把值转成小写;
<p>{{ 'HELLO' | lower }}</p>
upper:把值转成大写;
<p>{{ 'hello' | upper }}</p>
title:把值中的每个单词的首字母都转成大写;
<p>{{ 'hello' | title }}</p>
trim:把值的首尾空格去掉;
<p>{{ ' hello world ' | trim }}</p>
reverse:字符串反转;
<p>{{ 'olleh' | reverse }}</p>
format:格式化输出;
<p>{{ '%s is %d' | format('name',17) }}</p>
striptags:渲染之前把值中所有的HTML标签都删掉;
<p>{{ 'hello' | striptags }}</p>
支持链式使用过滤器:
<p>{{ “ hello world “ | trim | upper }}</p>
(2)列表过滤器
first:取第一个元素
<p>{{ [1,2,3,4,5,6] | first }}</p>
last:取最后一个元素
<p>{{ [1,2,3,4,5,6] | last }}</p>
length:获取列表长度
<p>{{ [1,2,3,4,5,6] | length }}</p>
sum:列表求和
<p>{{ [1,2,3,4,5,6] | sum }}</p>
sort:列表排序
<p>{{ [6,2,3,1,5,4] | sort }}</p>
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 }}
<p>{{form.user_name}}</p>
{% for msg in form.user_name.errors %}
<p>{{msg}}</p>
{% endfor %}
{{form.user_name.errors}} # 校验失败的时候会弹出提示
验证器中:
user_name=StringField(label=u'用户名',validators=[DataRequired('这个是错误提示信息!')])
submit按钮也需要被抽像
6、宏
(1)模板中多次使用的内容可以被定义为宏;
{% macro input() %}
<input type="text"
name="username"
value=""
size="30"/>
{% endmacro %}
使用:
{{ input() }}
{% macro input2(type,value,size='30') %}
<input type="{{type}}"
name="username"
value="{{value}}"
size="{{size}}"/>
{% endmacro %}
使用:
{{ input('password','name') }}
(2)外部引用:文件名可以自定义macro.html
;
{% macro input() %}
<input type="text" name="username" placeholde="Username">
<input type="password" name="password" placeholde="Password">
<input type="submit">
{% 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 %}
模板继承使用时注意点:
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-8
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate,MigrateCommand
from flask_script import Shell,Manager
app = Flask(__name__)
manager = Manager(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/Flask_test'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
#第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例
migrate = Migrate(app,db)
#manager是Flask-Script的实例,这条语句在flask-Script中添加一个db命令
manager.add_command('db',MigrateCommand)
#定义模型Role
class 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()
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'
;templates
如果没有找到,再去定义蓝图的时候定义的模板目录里找。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
文件。