一:URL简介
1:定义
url是统一资源定位符(Uniform Resource Locator的简写),对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
2:组成
scheme://host:port/path/?parameter=xxx#anchor
https://www.baidu.com/Public/linux/?fr=aladdin#23scheme:代表的是访问的协议,一般为http或者https以及ftp等。
host:主机名,域名,比如www.baidu.com。
port:端口号。当你访问一个网站的时候,浏览器默认使用80端口。
path:路径。比如:www.baidu.com/Public/linux/?python=aladdin#23,www.baidu.com后面的Public/linux就是path。
query-string:查询字符串,比如:www.baidu.com/s?wd=python,?后面的python=aladdin就是查询字符串。
anchor:锚点,后台一般不用管,前端用来做页面定位的。比如:https://www.oldboyedu.com/Public/linux/?fr=aladdin#23 ,#后面的23就是锚点
3:作用
顾名思义统一资源定位符,是用来做定位用的,我们的web开发无非是要调用程序,而调用的具体程序我们称之为python的视图函数,URL建立了与Python视图函数一一对应的映射关系,通俗易懂可以理解为一条命令触发了一个python的函数或类。
二:URL使用方式
1:简介
在Flask程序中使用路由我们称之为注册路由,是使用程序实例提供的app.route()装饰器注册路由,而括号内的字符串就是url,注册路由的过程就是完成了 url和python类或函数映射的过程,可以理解为会有一张表保存了url与python类或函数的对应关系。这样我们以url访问flask就可以找到对应的程序
@app.route('/')defhello_world():return 'Hello World!'
2:url传参方式
2.1:动态传参
例如,你想根据学生的id找到具体的学生,http://127.0.0.1:5000/student_list// 仍然在path部分 ,但是你没必要写多个路由,我们Flask支持这种可变的路由。
@app.route('/student_list//')defstudent_list(student_id):return '学生{}号的信息'.format(student_id)
2.2:动态路由过滤
可以对参数限定数据类型,比如上面的文章详情,限定student_id必须为整数类型
@app.route('/student_list//')defarticle_detail(student_id):return '学生{}号的信息'.format(student_id)
主要有这几种类型过滤:
string: 默认的数据类型,接收没有任何斜杠" /"的字符串
int: 整型
float: 浮点型
path: 和string类型相似,但是接受斜杠,如:可以接受参数/aa/bb/cc/多条放在一起
uuid: 只接受uuid格式的字符串字符串,
3: url_for()的使用:
3.1简介视图函数:
我们在访问一个网址的时候在调用flask项目的时候需要调用的是一段具体的代码,也就是一个python类或者python函数,在这里这个python类我们称之为视图类,python函数我们称之为视图函数。
3.2 url_for()的作用:
如果我们在视图函数中想使用一个url,比如给前端返回,或者我们在这个视图函数中返回一个模板文件都会使用到url,url相当于一把钥匙可以开启一些资源。如果你修改了注册路由编写的url规则,相当于修改了钥匙。那么其他的视图函数依旧是使用了原来的钥匙就无效了,如果项目是一个大项目,你一点点手动的去改涉及到的的url就不合理了。url_for()就是用来解决这个问题的。
3.3url_for()的原理:
利用视图函数名字一般不会改变的特性,利用视图函数的名字去动态精准的获取url,以便于开发使用。
url_for('视图函数名字') #输出该视图函数url
from flask importFlask,url_for
app= Flask(__name__)
app.config.update(DEBUG=True)
@app.route('/',endpoint="sb")defindex():
real_url=url_for("sb")returnreal_urlif __name__ == '__main__':
app.run()
四:路由源码分析
from flask importFlask
app= Flask(__name__)
@app.route('/')defhello_world():return 'Hello World!'
if __name__ == '__main__':
app.run()
1:第一步
2:第二步
3:第三步
4:第四步
PS:
(1)此处装饰器参数f 即为上述被装饰的函数
(2)灵魂代码为:self.add_url_rule(rule, endpoint, f, **options)
self.add_url_rule(rule, endpoint, f, **options)
'''self 当前flask产生的对象 app
endpoint:函数别名
f:当前被装饰的函数'''
5:第五步
PS;
1:首先判断是否有别名 如果没有别名走该_endpoint_from_view_func方法
2:如果有别名使用自己的传入的别名
3:判断是否传入请求方式 如果没有传入请求方式 默认使用get方式
4:别名不能重复
4.1:
1:首先假设没有传入别名 即old_func为空 条件不成立
2:条件不成立 别名为当前函数名 此时别名不为空了
3:再次调用的时候 别名会有值 如果不和函数名相同 直接异常
4:如果别名相同 那么当调用函数的时候 有多个函数别名相同 该调用哪个函数
六:CBV
1:基本使用方式
from flask importFlask, views
app= Flask(__name__)
app.debug=TrueclassIndexView(views.View):defdispatch_request(self):print('Index')return 'Index!'
app.add_url_rule('/index', view_func= IndexView.as_view(name='index'))
2:问题探讨
(1)为什么as_view()括号内加上name
(2)为什么执行dispatch_request 而不是像django GET,POST等
3:源码分析
(1)走父类的as_view方法
@classmethoddef as_view(cls, name, *class_args, **class_kwargs):''':param cls:
:param name: 从代码中可以看到 name这个参数必须传递
:param class_args:
:param class_kwargs:
:return:
部分代码展示'''
def view(*args, **kwargs):
self= view.view_class(*class_args, **class_kwargs)return self.dispatch_request(*args, **kwargs)#view 上述view函数view.view_class= cls #view_class 绑定当前类
view.__name__ = name #将函数名称 更改为传过来的名称
return view #返回当前函数
PS:
1:假设上述不传递name这个参数 上述路由可以更改为
app.add_url_rule('/index', view_func=view)
2:从上述更改的路由可以看到 所有的路由都指向一个view函数
3:代码分析add_url_rule
if view_func is notNone:
old_func=self.view_functions.get(endpoint)if old_func is not None and old_func !=view_func:raiseAssertionError("View function mapping is overwriting an"
"existing endpoint function: %s" %endpoint
)
self.view_functions[endpoint]= view_func #根路由
PS:
(1)如果不传递name
(2)首先获取不到别名 别名默认为函数名
(3)当再次访问的时候 如果函数名不等于别名 则会直接抛出异常
def view(*args, **kwargs):
self= view.view_class(*class_args, **class_kwargs)return self.dispatch_request(*args, **kwargs)
1:上述self 为当前类名称
2:在类中可以调用dispatch_request方法
七:CBV改良模式
1:改良
classIndexView(views.MethodView):
methods=["GET","POST"]defget(self):print('Index')return 'Index!,get'
defpost(self):return 'Index!,post'
2:源码分析
def dispatch_request(self, *args, **kwargs):
meth=getattr(self, request.method.lower(), None)
if meth is None and request.method == "HEAD":
meth= getattr(self, "get", None)assert meth is not None, "Unimplemented method %r" %request.methodreturn meth(*args, **kwargs)
1