对Flask感兴趣的,可以看下这个视频教程:http://study.163.com/course/courseLearn.htm?courseId=1004091002

1. 第一个 flask 程序

# 从 flask 框架中导入 flask 类
from flask import Flask # 用 flask() 初始化一个 flask 对象,并赋给 app
# 需传递一个参数 __name__
# 1. 方便 flask 框架去寻找资源
# 2. 方便 flask 插件去定位问题
app = Flask(__name__) # @app.route() 是一个装饰器,作用是对 url 与 视图函数进行映射
# 将 `/` 映射到 hello_world() 函数上
# 即用户访问 http://example:80/ 的时候,用 hello_world() 函数来响应
@app.route('/')
def hello_world():
return 'Hello World!' # 如果当前文件作为程序入口,那么就执行 app.run()
if __name__ == '__main__':
# app.run() 是启动一个应用服务器来响应用户请求并不断监听
# app.run() 是 FLask 中的一个测试应用服务器(性能差,在部署的时候应该使用 uwsgi 而不是 app.run)
# app.run() 在底层实际上是一个 while(True) 循环,循环体是 listen() 函数,不断地监听指定端口号
app.run(debug=True,port=8000)

2. 使用 Debug 模式

使用 Debug 模式有很多好处:

1. 将报错信息显示到浏览器上,而不需要进入编辑器中查看报错信息,方便开发者查看错误
2. 当检测到程序代码(.py文件)发生改动,程序会自动加载而不需要手动重启服务器

对 flask 程序使用 debug 模式有 4 种方式,如下:

2.1 在 app.run() 中使用

app.run() 中直接传入一个关键字参数:app.run(debug=True)

2.2 在主 app 文件中使用 app.debug=True

from flask import Flask
app = Flask(__name__)
app.debug = True # 在主 app 文件中使用
…… 略 ……

2.3 在主 app 文件中使用 app.config.update(DEBUG=True)

from flask import Flask
app = Flask(__name__)
app.config.update(DEBUG=True) # 在主 app 文件中使用
…… 略 ……

使用 app.config.update(DEBUG=True) 这种方法实际上是借助了 Python 中的字典(Dict)属性,即:

a = {'a':1}
b = {'b':2}
a.update(b)
print(a) # {'a':1,'b':2}
a.update(c=3)
print(a) # {'a':1,'b':2,'c':3}

可以使用 print(isinstance(app.config,dict)) 来判断 app.config 是不是一个字典类型的数据。但是要注意 DEBUG 一定要大写。

以上这三种开启 Debug 模式的方法比较简单,还有一种开启 Debug 模式的方法需要借助配置文件,借助配置文件开启 Debug 模式的方法也比较规范,如下。

2.4 在配置文件中使用

  1. 在相同目录下,新建一个 python 文件,建议命名为 config,并在里面指定该程序配置了 DEBUG 模式,即 config.py 文件的内容如下:

     config.py
    
     # encoding:utf-8
    DEBUG = True
    # SECRET_KEY
    # SQLALCHEMY_DB # 数据库的一些参数配置
  2. 然后在主 app 文件中导入这个文件并配置到 app 中,主 app 文件内容如下:

     First_Flask.py
    
     # encoding:utf-8
    from flask import Flask
    import config # 导入 config 配置文件 app = Flask(__name__)
    app.config.from_object(config) # 将该配置文件的配置信息应用到 app 中 @app.route('/')
    def hello_world():
    a = 3
    b = 0
    c = a/b
    return 'Hello,World.' if __name__ == '__main__':
    app.run()

2.5 PIN 码

开启了 DEBUG 模式后,当程序抛出异常,则可以在网页上对程序进行调试,在网页上报出的任何一行错误信息中都有一个命令行小图标,点击该图标就可以进行调试了。

但是要注意,如果想要在网页上对程序进行调试,那么就需要输入 PIN 码,PIN 码在 Pycharm 中执行程序的时候会显示,复制过去粘贴即可。其中,PIN 码的有效时间是 8 小时,保存在浏览器的 Cookie 中,所以也不用每次抛出异常时都要输入一遍 PIN 码。

PIN 码的作用是为了保证程序更加安全,比如我不想让其他开发者知道我的代码写的是什么,但是实际上并没有什么卵用,因为都是开发者,没必要隐藏自己的代码。这个机制反而更加麻烦了一些。

3. 应用配置文件的两种方式

  1. 如上所示,在主 app 文件中导入 config 文件后,使用 app.config.from_object(config) 来将配置文件应用到 app 中,如下所示:

     from flask import Flask
    import config
    app = Flask(__name__)
    app.config.from_object(config)
  2. 不需要 import config,直接使用 app.config.from_pyfile 来将配置文件应用到 app 中,如下所示:

     from flask import Flask
    app = Flask(__name__)
    app.config.from_pyfile('config.py')

    实际上,from_pyfile 并不局限于 python 文件,也可以是其他类型的文件,如 config.txt

    from_pyfile 还有一个被隐藏的默认参数是 silent=False,所以完整格式是 app.config.from_pyfile('config.py',silent=False)。当 silent 被置为 False 时,如果前面输入的文件不存在,则抛出异常;当 silent 被置为 True 时,则会忽略这种错误。

4. URL 传参到视图

参数的作用:可以在相同的 URL 但是指定不同的参数时,来加载不同的数据。

如:http://localhost:8000/article/abchttp://localhost:8000/article/def 中,两条 URL 的参数不同,我们可以获取这个参数并渲染后返回客户浏览器

如何传参:如何在 flask 中使用参数?有两种方式实现。

  1. 第一种,使用 path 的形式,将参数嵌入到路径中

    传递参数的语法是:/<参数名>/,在对应的视图函数中也要定义相同的参数名。如下代码所示:

     @app.route('/article/<id>')
    def article(id):
    return u'<h1>你请求的参数是:%s<h1>' % id

    如果要限制传入参数的数据类型,可以这么定义:/article/<数据类型:参数名>,如 /<int:id>/,如下:

     @app.route('/article/<int:id>')
    def article(id):
    return u'<h1>你请求的参数是:%s<h1>' % id

    对于这段代码,当浏览器中的 url 是 127.0.0.1:5000/article/1 时能正确返回,当 url 是 127.0.0.1:5000/article/abc 时则提示 not found。如果没有指定数据类型,则默认是 str 型。

    其中,这些类型可以是:

     string	默认的数据类型,接受没有斜杠"/"和"\"的任何字符
    int 只接受整型
    float 只接受浮点型
    path 与 string 类似,但是接受斜杠
    uuid 只接受 uuid 字符串,其中 uuid 是全球唯一的字符串,一般可以用来作为表的主键
    any 可以指定多种路径,示例说明:
    any 示例:
    @app.route('/<any(article,user):url_path>/<id>')
    def detail(url_path,id):
    return '详情页面,id=%s' % id
    # 这个方法用于不同的 url 对应相同的视图函数的需求
    # 例如:/article/1 和 /user/1 对应同一个视图函数
  2. 第二种,使用查询的方式,调用 request.args.get('args') 方法,获取问号传递的参数

     from flask import request
    …… 略 ……
    @app.route('/keyword/')
    def keyword_args():
    wd = request.args.get('wd')
    return '?后面的参数是:%s' % wd

    这样,就可以获取 url 后面以问号的形式跟上的关键字了,如:/keyword/?wd=python。如果需要传递多个参数,那么问号后面可以跟 & 符号进行连接,如:/keyword/wd=python&name=myyd

    那么在视图函数中再加上 name = request.args.get('name') 即可。

5. URL 反转

正转指的是:在获取到用户输入的 URL 后将该 URL 映射到对应的视图函数中,让对应的视图函数去处理该用户的请求;

反转指的是:与正转相反,通过视图函数来查找对应的 URL。

反转的作用是:1. 在页面重定向的时候会使用 URL 反转;2. 在模板中会使用 URL 反转

实现反转的方法:

  1. 在 flask 框架中导入 url_for 模块

  2. url_for('FunctionName',key=value) 实现反转

    第一个参数 FunctionName 是视图函数的函数名。

    第二个参数 key=value 是传递给视图函数的参数,即 @app.route('/article/<id>') 中的 id。如果这个参数在 @app.route() 时已被定义,则该参数则以 path 的形式出现在 url 中;如果这个参数在 @app.route() 时未被定义,则该参数通过问号 ? 跟在 url 的后面传递给后台。

    例如:

     @app.route('/article/<id>')
    def article(id):
    return 'article' print(url_for('article',id='123',name='myyd')) # /article/123?name=myyd
  3. 源代码如下

     from flask import Flask,url_for
    import config app = Flask(__name__)
    app.config.from_object(config) @app.route('/')
    def hello_world():
    print(url_for('article',id='123')) # /article/123
    print(url_for('article',id='123',name='myyd')) # /article/123?name=myyd
    print url_for('my_list') # /list/
    return 'Hello,World.' @app.route('/article/<id>/')
    def article(id):
    return u'<h1>你请求的参数是:%s<h1>' % id @app.route('/list/')
    def my_list():
    return '<h1>list</h1>' if __name__ == '__main__':
    app.run()

为什么需要 url_for ?

  1. 将来如果修改了 URL,但是没有修改 URL 对应的函数名,就不用到处去替换 URL 了。

  2. url_for 会自动地处理 URL 中的特殊字符(如"/"),不需要手动处理。

    如:print(url_for('article',next='/')) 会输出 /article/%2F,因为 "/" 在 URL 中有歧义。

6. 自定义 URL 转换器

客户提出两个需求

6.1 需求一:

在一个 URL 中,含有手机号码的变量,必须限定这个变量的字符串格式满足手机号码的格式。

为了实现这个需求,需要做如下几个步骤:

  1. 从 werkzeug.routing 导入 BaseConverter:from werzeug.routing import BaseConverter

  2. 实现一个类,继承自 BaseConverter,重写正则表达式

    查看 BaseConverter 中的底层定义:光标停留在 BaseConverter 上,按 Ctrl+B 组合键进入 BaseConverter 的定义代码,参考 PathConverter() 类的定义,依葫芦画瓢自定义一个手机号码格式的转换器。

     # PathConverter(葫芦)
    class PathConverter(BaseConverter):
    regex = '[^/].*?' # TelephoneConverter(瓢)
    class TelephoneConverter(BaseConverter):
    regex = '1[34578]\d{9}' # \d 代表数字,{9} 代表重复 9 次
  3. 添加自定义转换器到默认转换字典

    Flask 中原来就定义的转换器有:string、int、float、path、uuid、any 等,如下所示:

     DEFAULT_CONVERTERS = {
    'default': UnicodeConverter,
    'string': UnicodeConverter,
    'any': AnyConverter,
    'path': PathConverter,
    'int': IntegerConverter,
    'float': FloatConverter,
    'uuid': UUIDConverter,
    }

    所以我们需要将自定义的转换器也添加进来,有两种方式:第一种就是按照格式在 DEFAULT_CONVERTERS 中添加;第二种方式是借助 url_map 来实现,如下:

     app.url_map.converters['tel'] = TelephoneConverter
  4. 限制视图函数中的参数类型

     @app.route('/telephone/<tel:number>')	# 限制类型
    def telephone(number):
    return 'Number is %s' % number

6.2 需求二:

在一个 URL 中,包含 a+b 的 path,需要将其拆分为 ab,后台再进行处理。

传统方法如下:

在视图函数中对传进来的参数进行拆分:

@app.route('/list/<id>')
def my_list(id):
id_list = id.split('+')
return 'the id list is %s' % id_list
# 若浏览器地址栏的 url 写的是:127.0.0.1:5000/list/a+b
# 则返回页面的信息是:the id list is ['a','b'],而不是:the id list is a+b

对于传进来的参数,在调用视图函数时都要进行一次拆分,会降低执行效率,能否在传到视图函数之前就已经对 a+b 格式的参数进行拆分?

借助 URL 转换器:

在 URL 转换器中定义了一个两个函数:to_python()to_url()

  1. 前者的作用是:将 URL 中的参数经过解析后传递给视图函数,即在 to_python 函数体中解析 URL 中的参数,然后 return 到视图函数中作为参数,如下:

     class ListConverter(BaseConverter):
    def to_python(self,value): # value 就是 /list/ 后面本来要跟的 a+b
    return 'value.split('+')' # 然后以 ['a','b'] 的格式返回给视图函数 my_list()

    然后要记得添加到默认的转换器字典中:app.url_map.converters('List') = ListConverter,最后限制类型:@app.route('/list/<List:id>')

    这样,视图函数就不用再进行拆分处理,而是能直接拿到最终想要的内容。

  2. 后者的作用是:在使用 url_for 时将参数还原成 url,如下:

     class ListConverter(BaseConverter):
    def to_url(self,value): # value 就是从视图函数中传过来的参数 ['a','b']
    return "+".join(value) # 然后以 a+b 的格式返回给 url_for 的参数 @app.route('/')
    def index():
    return url_for('my_list',id=['a','b'])

注意:这两个函数是成对出现的,一般情况下,要解析也要还原。

源代码如下

from flask import Flask,url_for
from werkzeug.routing import BaseConverter class ListConverter(BaseConverter):
def to_python(self, value):
return value.split('+')
def to_url(self, value):
return "+".join(value) app = Flask(__name__)
app.url_map.converters['List'] = ListConverter @app.route('/')
def hello_world():
return url_for('my_list',id=['a','b']) @app.route('/list/<List:id>/')
def my_list(id):
return 'The List is %s' % id if __name__ == '__main__':
app.run(debug=True)

7. Flask 开发的小细节

  1. 想要让自己写的网站,在局域网中被其他网络设备访问,则必须指定 host,即 app.run(host='0.0.0.0'),同时还需要注意以下 3 点:

  2. 指定端口号:Flask 的默认端口号是 5000,如果想要改成 8000 端口,应将 app.run 写成 app.run(port=8000)

  3. URL 唯一

    在定义 URL 的时候,一定要记得在最后加一个 /,这是为了更好的用户体验。而且搜索引擎会将加了斜杠的和不加斜杠的 URL 视为两个不同的 URL,但实际上加不加斜杠都是同一个 URL,这样就会给搜索引擎造成一个误解。

  4. 指明 GET 或者 POST 请求

    参考我的另一片博客:Flask基础,第 10 点:GET 、POST 和 钩子函数。

8. 页面跳转和重定向

重定向指的是浏览器自动地从一个页面跳转到另一个页面,可以用在一些需求上,如:用户访问某些需要登录的页面时,如果用户没登录,则可以让他重定向到登录页面。重定向分为两种:永久性重定向和暂时性重定向。

8.1 永久性重定向

状态码是 301,多用于旧网址被废弃了要转到一个新网址上,如京东网站,当你访问 www.jingdong.com 时会被重定向到 www.jd.com,因为旧网址已经被弃用了,所以这种情况应该使用永久重定向。

8.2 暂时性重定向

状态码是 302,表示页面的暂时性跳转。比如访问一个需要权限的网页,如果当前用户没有登录,应该重定向到登录页面。这种情况下应该使用暂时性重定向。

8.3 重定向的实现

在 Flask 中,重定向是通过 flask.redirect(location,code=302) 这个函数来实现的。其中:locate 代表重定向之后的 URL,应该配合之前将的 url_for() 来使用,code 表示使用的状态码,默认是 302。

看一个具体的例子:

from flask import Flask,redirect,url_for,request

app = Flask(__name__)
app.debug = True @app.route('/')
def index():
return 'hello world' @app.route('/login/')
def login():
return '请登录!' @app.route('/profile/')
def profile():
name = request.args.get('name')
if name:
return '个人详情页面'
else:
return redirect(url_for('login')) if __name__ == '__main__':
app.run(host='0.0.0.0')

9. 视图函数 response 返回值详解

Flask 的视图函数默认只可以返回字符串、元组合 Response 对象,Flask 转换响应对象的逻辑是:

  1. 如果返回的是一个合法的相应对象,则直接返回;

  2. 如果返回的是一个字符串:

    则 Flask 会构建一个 werkzeug.wrappers.response 对象,response 对象会将该字符串作为主体,状态码为 200,MIME 类型为 text/html,即构建成为:response('string',status=200,mimetype='text/html') 然后返回 response 对象。我们在视图函数中使用 return 返回内容,实际上就是 Flask 帮我们完成的这个动作。

    所以视图函数中的 return 'Hello World!' 等价于 return response('Hello World!')

  3. 如果返回的是一个元组:

    元组的数据类型是(response,status,headers),其中,status 会覆盖默认的 200 状态码,header 可以是一个列表或者字典,作为额外的消息头。

  4. 如果非以上内容:

    Flask 会去底层调用 Response.force_type(rv,request,environ) 返回一个 response 对象。这样,视图函数在调用 return 的时候就可以正确返回了。如下例:

     from flask import Flask,Response,jsonify
    
     app = Flask(__name__)
    app.debug = True class JSONResponse(Response): @classmethod
    def force_type(cls, response, environ=None):
    '''
    这个方法只有在视图函数返回非字符串、非元组、非response对象的时候被调用
    response:视图函数的返回值
    '''
    print(response)
    print(type(response))
    # jsonify:除了将字典转换成json对象,还将该对象包装成了一个Response对象
    if isinstance(response,dict):
    return super(JSONResponse,cls).force_type(response,environ) app.response_class = JSONResponse @app.route('/dict/')
    def dict():
    return {'username':'myyd','age':18} if __name__ == '__main__':
    app.run(host='0.0.0.0')

    实现响应自定义内容,需要完成 3 个步骤:

    1. 继承自 Response
    2. 实现方法 force_type(cls,response,environ=None)
    3. 指定 app.response_class 为你自定义的 Response 对象

Flask-论坛开发-1-基础知识的更多相关文章

  1. ArcGIS API for JavaScript开发初探——基础知识

    1.前言 在ArcGIS Web API开发体系中一共有四大类,分别为: ArcGIS API for Flex ArcGIS API for JavaScript ArcGIS API for RE ...

  2. Java开发培训基础知识解析之反射机制

    Java是老牌编程语言,是当前应用最广泛的编程语言之一.想要学习Java你就一定要掌握Java基础知识,而反射对于初学Java的人来说绝对是非常重要的知识点.什么是反射?如何理解反射机制?如何使用反射 ...

  3. 【千纸诗书】—— PHP/MySQL二手书网站后台开发之基础知识

    前言: 在具体回顾每一个功能的实现前,还是有必要先温习一些项目涉及到的PHP.MySQL[语法基础].项目github地址:https://github.com/66Web/php_book_stor ...

  4. ArcGIS Engine开发前基础知识(4)

    ArcGIS不同开发方式的比较 关于GIS应用软件的开发,通常有三种方式:C/S架构.网络GIS和移动GIS.ArcGIS平台提供了对三种开发方式的支持,对于采用从C/S架构的大多数开发者来讲,首先想 ...

  5. ArcGIS Engine开发前基础知识(3)

    对象模型图 一.对象模型图中的类与接口 ArcGIS Engine 提供大量的对象,这些对象之间存在各种各样的关系,如继承.组合.关联等.对象模型图(Object model diagram,ODM) ...

  6. ArcGIS Engine开发前基础知识(1)

    ArcGIS二次开发是当前gis领域的一项重要必不可少的技能.下面介绍它的基本功能 一.ArcGIS Engine功能 在使用之前首先安装和部署arcgis sdk,(在这里不在赘述相关知识)可以实现 ...

  7. Python开发——1.基础知识

    一.开发 开发语言分为高级语言和低级语言 高级语言:Python.Java.PHP.C++.C#.GO.Ruby等:低级语言:C.汇编语言. 高级语言对应的是字节码,是将代码编译成字节码,然后交给机器 ...

  8. android开发学习---基础知识学习、如何导入已有项目和开发一个电话拨号器

    一.基础知识点学习  1.Android体系结构 如图所示,android 架构分为三层: (1)最底层是linux内核,主要是各种硬件的驱动,如相机驱动(Camera Driver),闪存驱动(Fl ...

  9. Unity游戏开发面试基础知识

    面试第一次知识总结: 一.Unity基本操作 1.unity提供哪几种光源? 点光源.平行光.聚光灯.区域光. 2.物体发生碰撞的必要条件什么? 两个物体必须有碰撞体Collider组件,一个物体上必 ...

  10. ArcGIS Engine开发前基础知识(2)

    ArcGIS基本控件简介 ArcGIS Engine控件是一组可视化的开发组件,每个ArcGIS Engine控件都是一个COM组件.这些组件包括MapControl,PageLayoutContro ...

随机推荐

  1. 关于hover和after、before合用

    通常hover后面跟的选择器,都是在myClass结构之下 的dom元素. 如果想在myClass下添加after等,就需要两个::号. 注:after/before是属于myclass的下级元素,并 ...

  2. github拓展,以及ModelForm的使用

    github - git  init/add/commit/reset/log/status/stash pop/checkout/branch    新入职到公司,地址:   git clone h ...

  3. Java没有头文件的原因

    http://bbs.csdn.net/topics/100134244 C/C++ 之所以需要头文件(.h),有两个用处,一个是在开发编译的时候,在各个编译单元(Compile Unit)之间共享同 ...

  4. P1481 魔族密码 (LIS)

    题的连接:https://www.luogu.org/problemnew/show/P1481 简单思路: 就是LIS,最长上升子序列,当然把条件改一下,从模板里的A[ i ]> A[ j ] ...

  5. go标准库的学习-crypto/des

    参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/des" des包实现了DES标准和TDEA算法,参见U.S. Fed ...

  6. OpenCV (C++) 颜色跟随

    #include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; ...

  7. 国产的骄傲,Deepin发布v15.9

    深度操作系统是一个致力于为全球用户提供美观易用.安全可靠的Linux发行版.深度操作系统基于Linux内核,以桌面应用为主的开源GNU/Linux操作系统,支持笔记本.台式机和一体机.深度操作系统(d ...

  8. PAT A1076 Forwards on Weibo (30 分)——图的bfs

    Weibo is known as the Chinese version of Twitter. One user on Weibo may have many followers, and may ...

  9. 【Codeforces 464D】World of Darkraft - 2

    Codeforces 464 D 首先我们知道这K个装备是互不干扰的,就是说如果一个装备升级了或者卖掉了,不会对其它装备的挣到的钱产生任何影响.所以我们就考虑单独处理某一个装备挣到的钱. 那么就设\( ...

  10. 【Codeforces 204E】Little Elephant and Strings

    Codeforces 204 E 题意:给\(n\)个串,求对于每一个串在至少\(k\)个串中出现的它的子串\(S_{l..r}\)有多少个. 思路:后缀自动机上\(dp\)... 我们首先构造出这\ ...