Flask(URL)
url详解
URL是Uniform Resource Locator的简写,统一资源定位符
一个URL由以下几部分组成:
scheme://host:port/path/?query-string=xxx#anchor
scheme:代表的是访问的协议,一般为http 或者https以及ftp等
host:主机名,域名,比如
port:端口号。当你访问一个网站的时候,浏览器默认使用80端口
path:查找路径. 比如,后面的trending/now 就是path
query-string:查询字符串 比如:,后面的wd=python就是查询字符串
anchor:锚点,后台一般不用管,前端用来做页面定位的
在浏览器中请求一个url,浏览器会对这个url进行一个编码。除英文字母,数字和部分符号外,其他的全部使用百分号+十六进制码值进行编码
flask简介
flask是一款非常流行的python web框架,flask能如此流行的原因可以分为以下几点:
微框架、简洁、只做他需要做的,给开发提供了很大的扩展性
Flask和相关的依赖设计得非常优秀,用起来很爽
开发效率非常高,比如使用SQLAlchemy的ORM操作数据库可以节省开发者大量书写sql的时间
社会活跃度非常高
Flask的灵活度非常之高,他不会帮你做太多的决策,即使已经帮你做出选择,你也能非常容易的更换成你需要的,比如:
使用Flask开发数据库的时候,具体是使用SQLAlchemy还是MongoEngine或者是不用ORM而直接基于MySQL-Python这样的底层驱动进行开发都是可以的,选择权完全掌握再你自己手中。区别于Django,Django内置了非常完善和丰富的功能,并且如果你想替换成你自己想要的,要么不支持,要么非常麻烦
把默认的Jinija2模板引擎替换成Mako引擎或者是其他模板引擎都是非常容易的
debug笔记
为什么需要开启DEBUG模式:
如果开启了DEBUG模式,那么再代码中如果抛出了异常,再浏览器的页面中可以看到具体的错误信息,方便开发者调式
如果开启了DEBUG模式,那么以后再python代码中修改了任何代码,只要按‘ctrl+s‘,‘flask‘就会自动的重新记载整个网站。不需要手动点击重新运行
配置DEBUG模式的四种方式
在‘app.run()‘中传递一个参数‘debug=True‘ 就可以开启‘DEBUG‘模式
给‘app.debug‘ = True 也可以开启‘debug‘模式
通过配置参数的形式设置DEBUG模式:‘app.config.update(DEBUG=True)‘
通过配置文件的形式设置DEBUG模式 ‘app.config.from_object(config)‘
PIN码
如果想要在网页上调式代码,那么应该输入‘PIN码‘
config笔记:
使用‘app.config.from_object‘的方式加载配置文件:
1.导入import config
2.使用app.config.from_object(config)
使用app.config.from_pyfile的方式加载配置文件
这种方式不需要import,直接使用‘app.config.from_pyfile(‘config.py‘)就可以了
注意这个地方,必须要写文件的全名,后缀名不能少
1.这种方式,加载配置文件,不局限于只能使用‘py‘文件,普通的‘txt‘文件同样也适合
2.这种方式,可以传递‘silent=True‘,那么这个静态文件没有找到的时候,不会抛出异常
URL与函数的映射:
从之前的helloworld.py文件中,我们已经看到,一个URL要与执行函数进行映射,使用的是@app.route装饰器。@app.route装饰器中,可以指定URL的规则来进行更加详细的映射,比如现在要映射一个文章详情的URL,文件详情的URL是/article/id/,id有可能为1、2、3....那么可以通过以下方式:
传递参数的语法是: ‘/< 参数名>/‘ .然后再视图函数中,也要定义同名的参数
@app.route(‘/article/< id>/‘)def article(id): return ‘%s article detail‘ %id
其中< id>,尖括号是固定写法,语法为< variable_name>,variable_name默认的数据类型是字符串。如果需要指定类型,则要写成< converter:variable_name>,其中converter就是类型 名称,可以有以下几种
string:默认的数据类型,接受没有任何斜杆‘\/‘的文本
int:接受整型
float:接受浮点类型
path:和string的类似,但是接受斜杆
uuid:只能接受uuid字符串 uuid是一个全宇宙都唯一的字符串,一般可以用来作为表的主键
any:可以指定多种路径,这个通过一个列子来进行说明:
@app.route(‘/< any(article,blog):url_path>/‘) def item(url_path): return url_pth
以上列子中,item这个函数可以接受两个URL,一个是/article/,另一个是/blog/.并且,一定要传url_path参数,当然这个url_path的名称可以随便
如果不想定制子路径来传递参数,也可以通过传统的?=的形式来传递参数,列如/article?id=xxx,这种情况下,可以通过request.args.get(‘id‘)来获取id的值。如果是post方法,则可以通过request.form.get(‘id‘)来进行获取
接受用户传递的参数:
第一种:使用path的形式(将参数嵌入到路径中),就是上面讲的
第二种:使用查询字符的方法,就是通过?key=value的形式传递的 如果想要进行多个查询传递,使用?key=value&key=value的方式
@app.route(‘/d/‘) def d(): wd = request.args.get(‘wd‘) return ‘您通过查询字符串的方式传递的参数是 :%s‘%wd
如果你的这个页面想要做‘SEO‘优化,就是被搜索引擎搜索到,那么推荐使用第一种形式(path的形式),如果不在乎搜索引擎优化,那么就可以使用第二种(查询字符串的形式)
url_for使用详解
一般我们通过一个url就可以执行到某一个函数,如果反过来,我们知道一个函数,怎么去获得这个url呢?url_for函数就可以帮我们实现这个功能,url_for()函数接收两个及以上的常数,他接收函数名作为第一个参数,接收对应URL规则的命名参数,如果还出现其他的参数,则会添加到url的后面作为查询参数
url_for的基本使用:
url_for第一个参数,应该是视图函数的名字的字符串。后面的参数就是传递给url
如果传递的参数之前在url中已经定义了,那么这个参数就好被当成path的形式给url,如果这个参数之前没有在url中定义,那么将变成查询字符串的形式放到url中
举例:
+ @app.route(‘/post/list/< page>/‘) + def my_list(page): + return ‘my_list‘ + print(url_for(‘my_list‘,page=1,count=2)) + 构建出来的url: /my_list/1/?count=2
为什么需要url_for
将来如果修改了url,但没有修改该URL对应的函数名,就不用到处去替换URL了
url_for会自动的处理那些特殊的字符,不需要手动去处理
url = url_for(‘login‘,next=‘/‘) #会自动的将/编码,不需要手动去编码 url = /login/?next=%2F
强烈建议在使用url的时候,使用url_for来反转url
自定义URL转换器
刚刚在URL映射的时候,我们看到了Flask内置了几种数据类型的转换器,比如有 int/string等。如果Flask内置的转换器不能满足你的需求,此时你可以自定义转换器。自定义转换器,需要满足以下几个条件:
1.转换器是一个类,且必须继承自werkzeug.routing.BaseConverter
2.在转换器类中,实现to_python(self,value)方法,这个方法的返回值,将会传递到view函数中作为参数
3.在转换器中,实现to_url(self,values)方法,这个方法的返回值,将会在调用url_for函数的时候生成符合要求的URL形式
比如,拿一个官方的列子来说,Reddit可以通过URL中用一个加号(+)隔开社区的名字,方便同时查看来自多个社区的帖子。比如访问‘\/r/\flask+lisp/\ ‘的时候,就同时可以查看flask和lisp两个社区的帖子,现在我们自定义一个转换器来实现
+ from flask import Flask,url_for + from werkzeug.routing import BaseConverter + class ListConverter(BaseConverter): + def __ init __(self,url_map,separator="+") + super(ListConverter,self).__ init__(url_map) + self.separator = separator + def to_python(self,value): + return value.split(self.separator) + def to_url(self,values): + return self.separtator.join(BaseConverter.to_url(self,value) for value in values) + app.url_map.converters[‘list‘] = ListConverter
自定义URL转换器的方式:
实现一个类,继承自"BaseConverter"
在自定义的类中,重写"regex",也就是这个变量的正则表达式
将自定义的类,映射到app.url_map.converters上。比如
app.url_map.converters[‘tel‘] = TelephoneConverter
to_python的作用
这个方法的返回值,将会传递到view函数中作为参数
to_url的作用
这个方法的返回值,将会在调用url_for函数的时候生成符合要求的URL形式
必会的小细节知识点
1.在局域网中让其他电脑访问我的网站
如果想在同一局域网下的其他电脑访问自己电脑上的Flask网站,那么可以设置host=‘0.0.0.0‘才可以访问得到
2.指定端口号
flask项目,默认使用5000端口,如果想更好端口,那么可以设置port=9000
3.url唯一
在定义url的时候,一定要记得在最后加一个斜杠
如果不加斜杠,那么在浏览器中访问这个url的时候,如果最后加了斜杠,那么就访问不到。这样用户体验不太好
搜索引擎会将不加斜杠的和加斜杠视为两个不同的url。而其实加和不加斜杠的都是同一个url,那么就会给搜索引擎造成一个误解。加了斜杠,就不会出现没有斜杠的情况
4.GET请求和POST请求
在网络请求中有许多请求方式,比如 GET、POST、DELETE、PUT请求等,那么最常用的就是GET和POST请求了
GET请求: 只会在服务器上获取资源,不会更改服务器的状态,这种请求方法推荐使用GET
POST请求: 会给服务器提交一些数据或者文件,一般POST请求是会对服务器的状态产生影响,那么这种请求推荐使用POST请求
关于参数传递:
GET请求:把参数放到url中,通过‘?xx=xxx‘的形式传递的 。因为会把参数放到url中,如果视力好,一眼就能看到你传递给服务器的数据。这样不太安全
POST请求:会把参数放到‘Form Data‘中。会把参数放到"Form Data"中,避免了被偷瞄的风险.但是如果别人想要偷看你的密码,那么其实可以通过抓包的形式。 因为POST请求可以提交一些数据给服务器,比如可以发送文件,那么这就增加了很大的风险。所以POST请求,对于那些有经验的黑客来讲,其实是更不安全的
在‘Flask’中,‘route‘方法,默认将只能使用‘GET‘的方式 请求这个url,如果想要设置自己的请求方式,那么应该传递一个‘methods‘参数
页面跳转和重定向;
重定向分为永久性重定向和暂时性重定向,在页面上体现的操作就是浏览器会从一个页面自动跳转到另外一个页面。比如用户访问了一个需要权限的页面,但是该用户当前并没有登录,因此我们应该给他重定向到登录页面
永久性重定向:
http的状态码是301,多用于旧网站被废弃了要转到一个新的网站确保用户的访问,最经典的就是京东网站,你输入的时候,会被重定向到,因为jingdong.com这个网址已经被废弃了,被改成jd.com,所以这种情况下应该用永久重定向
暂时性重定向
http的状态码是302,表示页面的暂时性跳转,比如访问一个需要权限的网址,如果当前用户没有登录,应该重定向到登录页面,这种情况下,应该用暂时性重定向
在FLask中,重定向是通过flask.redirect(location,code=302)这个函数来实现的,location表示需要重定向的url,应该配合之前讲的url_for()函数来使用,code表示采用哪个重定向,默认是302,也即是暂时性重定向,也可以修改成301来实现永久性重定向
以下来看一个列子,关于在flask中怎么使用重定向
+ from flask import False,url_for, redirect + app = Flask(__ name __) + app.debug =True + @app.route(‘/login/‘,methods=[‘GET‘,‘POST‘]) + def login(): + return ‘login page‘ + @app.route(‘/profile/‘,methods=[‘GET‘,‘POST‘]) + def profile(): + name = request.args.get(‘name‘) + if not name: + #如果没有name,说明没有登录,重定向到登录页面 + return redirect(url_for(‘login‘)) + else: + return name
视图函数 Response返回值详解
视图函数的返回值会被自动转换为一个响应对象,Flask的转换逻辑如下:
如果返回的是一个合法的响应对象,则直接返回
如果返回的是一个字符串,那么Flask会重新创建一个werkzeug.wrappers.Response对象,Response将该字符串作为主体,状态码是200,MIME类型为 text/html,然后返回该Response对象
如果返回的是一个元组,元组中的数据类型是(response,status,headers).status值会覆盖默认的200状态码,headers可以是一个列表或者字典,作为额外的消息头
如果以上条件都不满足,Flask会假设返回值是一个合法的WSGI t应用程序,并通过Response.force_type(rv,request.environ)转换为一个请求对象
以下用列子来进行说明
第一个列子:直接使用 Response创建
+ from werkzeug.wrappers import Response + @app.route(‘/about/‘) + def about(): + resp = Response(response=‘about page‘,status=200,content_type=‘text/html;charset=utf-8‘) + return resp
第二个例子:可以使用make_response函数来创建Response对象,这个方法可以设置额外的数据,比如设置cookie,header信息等
+ from flask import make_response + @app.route(‘/about/‘) + def about(): + return make_response(‘about page‘)
第三个列子: 通过返回元组的形式
+ @app.errorhandler(404) + def not_found(): + return ‘not found‘,404
第四个列子:自定义响应。自定义响应必须满足三个条件
必须继承自Response类
必须实现类方法 force_type(cls,rv,environ=None)
必须指定app.response_class为你自定义的Response
以下将用一个列子来进行讲解,Restful API都是通过JSON的形式进行传递,如果你的后台跟前台进行交互,所有的url都是发送JSON数据,那么此时你可以自定义一个叫做JSONResponse的类来代替Flask自带的Response类:
+ from flask import Flask,jsonify + from werkzeug.wrappers import Response + app = Flask(__ name __) + class JSONResponse(Response): + default_mimetype = ‘application/json‘ + @classmethod + def force_type(cls,response,environ=None) + if isinstance(response,dict): + jsonify除了将字典转换成json对象,还将该对象包装成了一个response对象 + response = jsonify(response) +return super(JSONResponse,cls).force_type(response,environ)) + app.response_class = JSONResponse + @app.route(‘/about/‘) + def about(): + return {‘message‘:‘about page‘} + if __ name __ == ‘__ main__‘: + app.run(port=8000) + 此时如果你访问/about/这个URL,那么在页面中将会显示: + { + ‘message‘:‘about page‘ + }
注意以上列子,如果不写app.response_class = JSONResponse,将不能正确的将字典返回给客户端。因为字典不再Flask的响应类型支持范围中,那么将调用的app.response_class这个属性的force_type类方法,而app.response_class的默认值为Response,因此会调用Response.force_class()这个类方法,他有一个默认的算法转换成字符串,但是这个算法不能满足我们的需求。因此,我们要设置app.response_class=JSONResponse,然后重写JSONResponse中的force_type类方法,在这个方法中将字典转换成JSON格式的字符串后再返回
视图函数中可以返回那些值:
1.可以返回字符串:返回的字符串其实底层将这个字符串包装成了一个‘Response‘对象
2.可以返回元组:元组的形式是(响应体,状态码,头部信息),也不一定三个都要写,写两个也是可以的。返回的元组,其实再底层也是包装成了一个‘Response‘对象
3.可以返回’Response‘及其子类
实现一个自定义的Response对象
1.继承自‘Response类‘
2.实现方法force_type(cls,rv,environ=None)
3.指定app.response_class 为你自定义的‘Response‘对象
4.如果视图函数返回的数据,不是字符串,也不是元组,也不是Response对象,那么就会将返回值传给‘force_type‘,然后再将force_type的返回值返回给前端