zoukankan      html  css  js  c++  java
  • Flask: Quickstart解读

    Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2

    从示例代码说起:

    1 from flask import Flask
    2 app = Flask(__name__)
    3 
    4 @app.route('/')
    5 def hello_world():
    6     return 'Hello, World!'

    第1行从flask模块导入Flask类;

    第2行定义一个Flask实例,每一个Flask实例都是一个WSGI应用(Application);

    参数是否为__name__是由模块是否 作为应用启动 还是 作为模块导入。在示例中,只有一个模块,并且是作为应用启动,因此,参数为__name__。

    在Flask的介绍文档中,Flask(...)函数是有多个参数的,这些参数用于指定应用怎么寻找模板、静态文件等。

    通常来讲,用户需要在 主模块或__init__.py文件 中创建Flask实例。

    第4行使用route函数告知Flask在接收到URL位“/”时交由hello_world函数处理;

    说明,截止此时, 我仍然不清楚如何创建更复杂的Flask应用——包含静态文件、模板文件、配置文件等的应用。

    在将示例程序改造为包形式时出现了下面的问题:

    1.文件夹下新建了__init__.py,并将Flask实例的创建代码放入其中;

    1 from flask import Flask
    2 
    3 app = Flask('HelloWorld')

    2.改造后的hello.py

    1 @app.route("/")
    2 def hello():
    3     return "Hello World!"

    3.运行应用

    跳转到HelloWorld的上一级目录Flask,下图为执行情况:Flask应用启动成功

    4.访问页面

    发生错误,没有显示hello.py模块中输出的Hello World!,如下图:

    后面又做了一下尝试,在__init__.py中添加了下面这句:

    from HelloWorld import hello

    结果,服务器运行不起来了,提示:

    File "C:Python36wsFlaskHelloWorldhello.py", line 1, in <module>
    @app.route("/")
    NameError: name 'app' is not defined

    app是在__init__.py中定义的,而hello.py模块并没有权限获取它吧?

    然后给__init__.py的app前加一个global关键字,结果,提示语法错误!

    app的定义要和其它URL的route调用放在同一个模块文件中?

    ……

    接下来,怎么办?(一筹莫展也和自己的Python基础有关系吧)

    ----

    在运行Flask项目时发现一个陷阱:Windows下SET命令设置环境变量时,等号前后不能有空格。

    下图是有空格的,启动Flask项目失败:

    下图么有空格,启动Flask项目成功:

    ----

    启动Flask项目的两种方式

    1.使用python -m flask run命令

    2.使用flask run命令(Python的Scripts添加到Windows的Path环境变量后可用)

    flask run还有更多参数可用,可以查看其帮助信息(flask run --help):

    补充说明:

    1.Flask项目如上面一样启动后,只能在本机访问;怎么让Flask项目可以被同网络的其它主机访问呢?使用-h/--host配置项绑定网卡地址;

    疑问:不知道是否支持IPv6地址。

    2.使用-h/--host配置项时,可以将参数设置为0.0.0.0,表示从本机的任何网卡都可以访问,如果固定到某一个IP地址,则只是绑定了那个IP地址所在

    网卡,此时只有那个IP所在网络的主机可以访问;

    在设置了-h/--host配置项启动时,Windows弹出了报警窗口:

    3.Flask项目的默认端口是5000,使用-p/--port来指定;

    还要检查所配置的端口是否被防火墙等软件屏蔽了,若是,需要开启。

    还有其它配置项,还需更多了解。

    ----

    开启调试模式,只需要在Flask项目启动时设置环境变量FLASK_ENV为development即可。

    当然,前面所述,也可以在启动时使用--debugger配置项打开。

    注意,一定要在生产环境中把调试器关闭!否则会有很大的安全隐患!

    使用调试器的更多信息,还需要学习实践。

    --

    Routing

    可以翻译为 URL路由,即定义Flask如何将各个URL请求进行转发,转发到函数,或者其它地方(哪里?尚不清楚)。

    route()函数用于将某个函数绑定到URL。

    示例:

    @app.route('/')

    @app.route('/hello')

    上面两个都是静态的URL,开发人员可以将URL变为动态的并绑定多个规则到一个函数(N URLs TO a FUNCTION)。 

    Quickstart中介绍了下面几种:

    1.变量规则(Variable Rules)

    在URL中添加变量部分:<变量名>

    函数会将收到的<变量名>作为关键词参数。

    还可以选择用转换器指定参数的类型:<转换器:变量名>

    转换器类型有5种:string, int, float, path, uuid (UUID string,见uuid模块)

    示例:

    @app.route('/user/<username>')

    @app.route('/post/<int:post_id>')

    @app.route('/path/<path:subpath>')

    2.唯一URL/重定向(Unique URLs / Redirection Behavior)

    说明,这一小节没看懂。

    Quickstart中举了下面两个例子:

    @app.route('/projects/')

    @app.route('/about')

    其中,第一个以斜杠结束,第二个没有斜杠。

    在访问第一个时,如果你没有加斜杠,那么,Flask会自动帮你跳转并添加;

    而在访问第二个时,如果加了斜线,那么抱歉,404等着你。

    好处是什么呢?

    帮助保证这些资源的URL唯一性,而这又可以帮助避免搜索引擎把相同的页面做两次索引。

    好吧,还是不太明白,但会是个好东西的。

    3.URL构建(URL Building)

    用处:给指定函数构建一个URL,使用url_for()函数。

    此函数接收的第一个参数为函数名,而其它有一些数量的参数被当作关键词参数,每一个都对应着URL规则的变量部分。

    还有一些不知道的变量部分被附加到URL后作为查询参数。

    为何要这么做呢?而不是如前面讲的硬编码到函数模板中?

    a.反转经常比硬编码有更多描述性东西;

    b.开发者可以一口气改变URL,而不需要记得去手动更改硬编码的URL;

    c.URL构建可以透明地处理特殊字符和Unicode字符的转义(escaping);

    d.产生的路径总是绝对路径,这避免了在浏览器中使用相对路径可能发生的一些非预期错误;

    e.如果你的应用放在了URL根目录之外,url_for()也可以正确的处理;(不明白,需要例子)

    Quickstart中举了一个例子,感觉它就是把几个url_for()函数转换的结果打印出来了,可是,对于项目的请求、响应有什么用呢?

    难道客户端只能使用url_for()转换的URL去访问?比如,那么,代码中的硬编码的例子还有效吗?

    4.HTTP方法

    route()函数的参数包括一个名为methods的,可以用来限制访问URL的请求方法(常见的请求访问有GET、POST,还有其它的)。

    示例:

    @app.route('/login', methods=['GET', 'POST'])

    上面的示例近允许了GET、POST方法的请求访问,其它的就不可以了。

    另外,GET方法允许后,HEAD方法自动就允许了。

    --

    静态文件(Static Files)

    在生产环境,HTTP服务器可以处理静态文件;但在开发过程中,Flask也可以处理静态文件。

    在package下建立一个名为static的文件夹,或者,和你的模块文件在同一级目录,然后,静态文件就可以以"/static"开头的URL进行访问了。

    --

    渲染模板(Rendering Templates)

    Flask自动配置了Jinja2模板引擎。可以使用render_template()函数渲染一个模板。开发者唯一要做的是,传递模板文件名和关键词参数给render_template()函数。

    示例:

    1 from flask import render_template
    2 
    3 @app.route('/hello/')
    4 @app.route('/hello/<name>')
    5 def hello(name=None):
    6     return render_template('hello.html', name=name)

    Flask会在templats文件夹中寻找模板文件,此文件夹和前面的static文件夹的位置相同,同级。

    模板怎么写?常见的HTML、JavaScript、CSS外, 就是模板相关的变量、标签、流程控制、过滤器、模板继承、自动转义等,在Jinja2中还发现一个新的Markup类

    更多关于模板的内容,还是要看看Jinja2的文档

    --

    访问请求数据(Accessing Request Data)

    Flask中提供了 全局的request对象 用来保存客户端请求的数据。

    为什么这个对象是全局的?Flask又是怎么做到线程安全的?哈,不懂,更不懂为何要提出这样的问题,好尴尬。

    因为Flask有一个 本地化上下文功能(Context Locals)

    此小节包含四部分:

    1.本地化上下文(下面主要是翻译Quickstart中的内容)

     Flask中的一些对象是全局的,这些对象实际上是 代理,代理的是本地的到一些具体的上下文的对象。

    把这些上下文想象成处理中的线程。一个请求近来,Flask决定新建一个线程。在Flask开始内部请求处理时,它清楚当前线程是 活跃的(active),并且

    绑定到当前的应用和WSGI环境。

    Flask再次用了一种智能的方法,因此,一个应用可以 不用中断 就发起(invoke)另一个应用。

    这对开发者有什么用啊?基本上是可以忽略的,除非要做单元测试类的工作。你会注意到,那些依赖于request对象的代码可能突然 因为没有request对象 而被打断。

    解决办法就是,创建你自己的 并 绑定到上下文中。

    Quickstart中还有两个关于 解决方案 的例子,大家可以去看看。

    1041.说实话,暂时没看明白这个。

    2.Request对象

    导入请求对象:

    from flask import request

    当前可用请求方法 通过method属性

    if request.method == 'POST':

    访问表单数据可以使用form属性

    request.form['username']

    request.form['password']

    说明,表单数据如果不在form属性中怎么办?KeyError!可以抓取到它并处理,或者,返回一个400页面。

    访问URL中提交的参数(?key=value)使用args属性

    searchwords = request.args.get('key', '')

    Flask推荐使用get方法获取,因为其已经对KeyError进行了处理,否则发生错误时返回不有好的400页面。

    更多关于request的内容,需要查看requst的文档

    3.文件上传

    使用Flask处理文件上传很容易。

    上传的文件被保存到 内存 或 文件系统中的某个临时位置。

    开发者可以通过reqest对象的files属性查看这些上传的文件。 

    这些文件表现的就像是Python文件对象,当仍然有一个save()方法可以让开发者可以将它们保存到服务器的文件系统中。

    例子:

    1 from flask import request
    2 
    3 @app.route('/upload', methods=['GET', 'POST'])
    4 def upload_file():
    5     if request.method == 'POST':
    6         f = request.files['the_file']
    7         f.save('/var/www/uploads/uploaded_file.txt')

    想要知道文件在客户端的名字?可以使用filename属性。但是千万注意,这个filename属性可能会被伪造,若是你需要使用这个属性,请将它

    传递给werkzeug模块的secure_filename()方法再用。

    例子:

    from flask import request
    from werkzeug.utils import secure_filename
    
    @app.route('/upload', methods=['GET', 'POST'])
    def upload_file():
        if request.method == 'POST':
            f = request.files['the_file']
            f.save('/var/www/uploads/' + secure_filename(f.filename))
        ...

    更多关于文件上传的内容,可以查看Flask的文件上传模式文档

    4.Cookies

    可以使用cookies属性访问cookies。 

    可以使用response对象的set_cookie方法设置cookie。

    注意,若是你要使用sessions,那么,请不要直接使用Cookies。因为Flask中的sessions是在cookies的上面添加了一些安全机制的。

    例子:读取cookies

    username = request.cookies.get('username')

    例子:存储cookies

    1 from flask import make_response
    2 
    3 @app.route('/')
    4 def index():
    5     resp = make_response(render_template(...))
    6     resp.set_cookie('username', 'the username')
    7     return resp

    注意上面的make_response()函数的用法:这个方法用于创建你自己的response对象,并可以使用新建对象给返回结果添加一些 头部信息,当然,也包括设置cookies了。

    --

    重定向和错误(Redirects and Errors)

    将用户重定向到另外的终端页面(endpoint),可以使用redirect()函数:

    return redirect(url_for('login'))

    P.S.看到了url_for()函数函数的用法,好开心。

    提前终止请求并返回一个错误码,可以使用abort()函数:此函数调用后的代码就 不会被执行了

    abort(401)

    定制错误页面 请使用errorhandler()装饰器:

    1 from flask import render_template
    2 
    3 @app.errorhandler(404)
    4 def page_not_found(error):
    5     return render_template('page_not_found.html'), 404 # 不要忘记这里的404

    --

    关于响应(About Responses)

     从一个视图函数返回的数据会被 自动转换成一个response对象。

    Flask采用的逻辑如下:

    a.如果response对象的类型正确,直接返回;

    b.如果是字符串,使用这个数据和默认参数创建一个response对象;

    c.如果是元组(tuple),元组的格式需要是(response, status, headers) 或者 (response, headers);P.S.这一段没翻译明白,也没弄太清楚

    d.如果上面的都不是,Flask会假设返回的数据时一个有效的WSGI应用,并将之转换为一个response对象。

    提示,如果开发者想要深入掌控response对象,可以使用make_response()方法。正如前面有提到——该header,用make_response()。

    详见Quickstart中例子。

    resp = make_response(render_template('error.html'), 404)

    --

    Sessions

    和请求对象相关联的是一个叫做session的对象,这个对象用于记录 具体用户访问应用时的 一些信息(什么信息?)。

    它是cookies上面实现的,并用加密的方式为cookies进行签名。这意味着,用户可以查看你的cookies的内容,但无法修改它,除非他们知道用于加密的密钥。

    P.S.有什么用?签名后的cookies是怎么样的?看来,自己还是缺乏经验啊,

    为了使用session,开发和需要设置应用的密钥(app.secret_key)(后文会讲怎么创建):

    1 # Set the secret key to some random bytes. Keep this really secret!
    2 app.secret_key = b'_5#y2L"F4Q8z
    xec]/' # 随机bytes

    看来这里设置后,Flask的sessions就使用这个密码去给cookies前面了啊。

    session的一些示例操作(下面的代码并非在一起的):

    1 return 'Logged in as %s' % escape(session['username'])
    2 ...
    3 session['username'] = request.form['username']
    4 ...
    5 # remove the username from the session if it's there
    6 session.pop('username', None)

    详见官网sessions文档

    怎么产生好的密钥(Hot to generate good secret keys)

    执行下面的命令:

    python -c "import os; print(os.urandom(16))"

    注意,用双引号,而不是单引号!Quickstart中的是错误的!

    注意,使用python3得到的和Quickstart中得到的不一样,不清楚怎么转换!

    如下图:Python3转换出来哦,好像还能看的懂,Python2的就……,看来要限制产生的字符的范围,比如,只能是数字、字母、标点符号等。

    注意:关于 基于cookies的sessions,Flask会获取你存储到sessions中的数据,并将它们序列化到cookie中。如果你发现某些数据在跨请求时没有

    找到,那么,在确认cookies在客户端使能了,也没有获得明显错误信息时,请检查页面响应中的cookies的长度和Web浏览器支持的长度。

    除了默认的基于客户端的sessions外,开发者还可以使用Flask的一些扩展模块去支持 服务器端sessions。

    问题:基于客户端sessions、基于服务器端sessions,两者的区别是什么?分别有什么用?TBD

    --

    Message flashing

    Flask使用flashing系统 给用户提供了一个简单的获取反馈的方法。

    flashing系统基本上实现了 在请求最后记录一个信息,并在下一个请求仅仅是下一个请求时读取它。

    这通常是和layout template联合使用以暴露信息。

    使用flash()函数flash一个消息,使用get_flashed_messages()函数获取所有消息。

    还不是太明白,,更多信息见官方文档

    --

    Logging

    浏览器访问不一定总是正确的,当错误、异常、恶意攻击等行为发生时,开发者应该记录相关问题。

    这时,就可以使用Flask提供的logger了,从Flask 0.3版本就预配置好了。

    Flask的logger是一个标准的日志记录器,可以到官网查看更多信息。 

    另外,关于应用可能发生的错误,请参考官网的应用错误文档。 

    --

    Hooking in WSGI中间件

    如果开发者想添加一个WSGI中间件到应用中,可以采用包装内部的WSGI应用。

    P.S.不明白有什么用

    --

    使用Flask扩展

    查找更多Flask扩展程序,请访问官网Extensions文档

    --

    部署到一个Web服务器

    请查看官方文档Deployment Options

    --

    后记:

    总算写完了,昨天下午+昨天晚上一小时+今天10点开工到现在。

    写完后,有什么进步吗?更牢靠了。可是,更熟练使用Flask了吗?

    况且Quickstart文档中的不少内容都没整明白。

    现在,要更进一步熟悉Flask需要:1.看更多文档、2.开发项目——在开发中学习。

    还要多练习。

    又是一篇长长的博文,也是醉了,感觉就是把Quickstart翻译了一遍,,至此,还有什么问题呢?

    声明:

    由于作者水平有限,如有错漏,请提醒通知。

  • 相关阅读:
    BFS 简单思想以及代码
    01、Hibernate安装配置
    WireShark——ARP 协议包分析
    eNSP之VLAN设计实验
    eNSP 交换机 路由器 PC 互连设计/实现
    Windows常用的网络命令
    01、Git安装教程(windows)
    Java IO编程——文件拷贝
    Java 多线程编程——多线程
    Java IO编程——转换流
  • 原文地址:https://www.cnblogs.com/luo630/p/9052738.html
Copyright © 2011-2022 走看看