pip install flask
其主要的依赖包:werkzeug、jinja2也会被一同install了;
app应用就是Flask的实例化对象,可以通过参数指定很多属性。详见Flask源码
from flask import Flask
# Flask类的对象就是一个app应用
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
'''
run_simple(host,port,app)
这里方法就是调用werkzeug里面的方法:
from werkzeug.serving import run_simple
'''
app.run()
Flask与Django都是python-web框架,Django有的功能,Flask也都有,只是Falsk较为零散,如果是开发一个较大的项目,使用Flask需要很强的代码编辑能力才能将代码写得非常有条理;Django则是初始化了很多内容,可以不做或者做很小的代码结构变动,按照其MVC/MTV模式,只需编写自己的业务功能;
Falsk是没有配置文件的;Falsk的配置可以简单的如下:
from flask import Flask
app = Flask(__name__)
app.secret_key = 'qwertyu'
app.debug = True # 自动重启最新代码,django是直接自动重启
上面的secret_key(俗称:盐,Flask用来加密session的)、debug都是属于Flask的配置;但是,想象一个大的项目,这样零散不统一放在一个文件下的代码多了,是很不便于维护和调试的;
所以需要我们自己创建一个专门用来放置配置代码的文件:settings.py配置项有很多:Flask官方文档-配置入门
规则:可以将不同的环境的服务器(测试服、正式服、预发布)写为不同的class,里面全部是静态变量,即:配置项;将不同环境共同的配置项写在一个基础class中,用于其他class继承;
# -----------------------settings.py
class BaseConf(object):
DEBUG = True
TESTING = False
DATABASE_URI = 'sqlite://memory:'
SECRET_KEY = '123@#@$$%%%^&MCL'
class ProductionConf(BaseConf):
DEBUG = False
DATABASE_URI = 'mysql://user@pro/foo'
class DevelopmentConf(BaseConf):
DATABASE_URI = 'mysql://user@dev/foo'
class TestingConf(BaseConf):
DATABASE_URI = 'mysql://user@test/foo'
有了settings.py,再需要在app应用中进行引用:
# 配置文件的导入方式
# app.config.from_object('settings.类名')
app.config.from_object('settings.TestingConf')
上面的代码过后,在需要的地方import,获取具体配置
from flask import current_app
# current_app.config就是settings文件中的所有;
current_app.config['KEY']获取KEY字段的值
视图函数在Django项目app应用的view中,而在Flask中,这是在app应用文件中,下面主要记录几个要点:
form flask import request
通过flask中的request包进行获取前端入参
# request.args:获取GET方式的入参,即:URL后面的参数
user = request.form.get('user')
# request.form:获取POST方式的入参,即:html页面表单form里面的数据
uid = request.args.get('uid')
form flask import session
# 把用户信息放入session
session["user_info"] = user
#Flask将session保存到浏览器的cookie中,而不是数据库了
#这里需要对session进行签名(俗称:加密),否则会报错;
#这里和app.secret_key给app加盐对应,Flask会根据app.secret_key给session加密
#此时,再去访问浏览器,请求登录后,浏览器接口可以看到对应的cookie是加密的;
# 从session中获取user_info,判断其是否是登录状态,否则直接跳转登录页面
user_info = session.get('user_info')
if not user_info:
return redirect("/login")
前端渲染和Django基本一样,只是说Django自带,Flask则是依赖jinja2;
<body>
<ul>
{% for k,v in user_dict.items() %}
<li> {{ v.name }}<a href="/detail?uid={{ k }}">查看详情</a></li>
{% endfor %}
</ul>
</body>
Flask的视图函数-后端响应的方式有两种:
# return render_template('login.html',msg = '用户名或密码错误!')
# render_template('login.html', **{'msg':'用户名或密码错误'}) ---》这种即便是Flask是通过**kwargs去响应数据给前端的;
# 响应页面及数据
return render_template('login.html',msg = '用户名或密码错误!')
# 重定向路径
return redirect("/login")
'''
查看Flask的app.route()的代码,发现里面是一个其实最核心的是执行了add_url_rule()
Flask添加路由的两种方式:
1.最常用的就是app.route("/index0",methods=['GET','POST'])装饰器;
2.也可使用app.add_url_rule('/',view_func=index,methods=['GET'])
'''
@app.route("/index0",methods=['GET','POST'])
def index0():
return ""
def index1():
return "1"
app.add_url_rule("/index1",view_func=index1,methods=['GET'])
在路由route装饰器中,endpoint参数就是别名,默认是视图函数名,反向生成路由时可以用到;
路由的url的方向生成,url_for():根据别名endpoint获取到视图函数对应的route;
作用:当你要redirect的url比较长,你可以使用url_for结合endpoint进行反向生成
url = url_for(别名):
@app.route("/logout",methods = ['GET'])
def logout():
url = url_for('in')# 这个“in”就是下面login函数的endpoint,即:别名
return redirect(url)
@app.route('/login',methods=['GET','POST'],endpoint='in')
def login():
return '登录页面'
'''
@app.route('/login',methods=['GET','POST'],endpoint='in')
路由系统:如果url需要代参数,那么Flask提供少有的固定格式,一个url后面可以接着多个参数,主要是
@app.route("/login/<username>")
@app.route("/login/<int:uid>")
@app.route("/login/<float:id>")
@app.route("/login/<path:path>")
也可自定义,百度:Flask路由正则扩展,可以查到代码,写一个类继承BaseConverter
from werkzeug.routing import BaseConverter
这里可以看出,route带参数的情况,其实使用url_for反向生成url时,也是可以传参的,根据要生成的URL的参数名
'''
@app.route('/test_login/<int:uid>')
def test_login(uid):
print(type(uid))# 这里是int类型,在url上获取的参数值都是str,但是Flask会根据你路由上的类型,自动给你转换为对应的类型
return str(uid)
上面代码框中的描述是Flask自有的几种路由入参方式,也可自定义,如下:
from flask import Flask, views, url_for
from werkzeug.routing import BaseConverter
app = Flask(import_name=__name__)
#1.写RegexConverter装换器类
class RegexConverter(BaseConverter):
"""
自定义URL匹配正则表达式
"""
def __init__(self, map, regex):
super(RegexConverter, self).__init__(map)
self.regex = regex
def to_python(self, value):
"""
路由匹配时,匹配成功后传递给视图函数中参数的值
:param value:
:return:
"""
return value
def to_url(self, value):
"""
使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
:param value:
:return:
"""
val = super(RegexConverter, self).to_url(value)
return val
#2.将转换器类添加到flask的默认路由系统字典中
app.url_map.converters['regex'] = RegexConverter
@app.route('/index/<regex("\d+"):nid>')#系统会给你自动匹配正则
#正则匹配成功后进入视图函数之前会调用to_python函数,进行二次处理
def index(nid):
print(nid)
return 'Index'
if __name__ == '__main__':
app.run()
路由的其他参数,很少使用的,
'''
defaults = {"db":"xxxx"},
redirect_to='/path',
strict_slashes=None等
'''
# url不传参数,但是你需要试图函数带一个默认参数
@app.route("/index_test",defaults={"db":"xxxxxxx"})
def index_test(db):
pass
# 新功能替换老功能时,url发生变化,但是希望访问老url重定向到新url
@app.route("/index_old",redirect_to='/index_new')
def index_old():
pass
# strict_slashes=True,必须按照路由route的路径访问,最后多加/符合是不行的
@app.route("/index_new",strict_slashes=True)
def index_new():
pass
# subdomain 子域名————暂不写了