【Flask】安装及入门

一、Flask安装

Flask 依赖两个外部库:Werkzeug 和 Jinja2 。 Werkzeug 是一个 WSGI(在 Web 应用和多种服务器之间的标准 Python 接口) 工具集。Jinja2 负责渲染模板。

那么如何在你的电脑上安装这一切?虽说条条大道通罗马,但是最强大的方式是 virtualenv ,所以我们首先来看它。

virtualenv

你很可能想在开发中用上 virtualenv,如果你有生产环境的 shell 权限,你同样会乐于在生产环境中使用它。

virtualenv 解决了什么问题?如果你像我一样喜欢 Python,不仅会在采用 Flask 的Web 应用中用上 virtualenv,在别的项目中你也会想用上它。你拥有的项目越多,同时使用不同版本的 Python 工作的可能性也就越大,或者起码需要不同版本的 Python 库。悲惨现实是:常常会有库破坏向后兼容性,然而正经应用不采用外部库的可能微乎其微。当在你的项目中,出现两个或更多依赖性冲突时,你会怎么做?

virtualenv 拯救世界!virtualenv 为每个不同项目提供一份 Python 安装。它并没有真正安装多个 Python 副本,但是它确实提供了一种巧妙的方式来让各项目环境保持独立。让我们来看看 virtualenv 是怎么工作的。

Mac OS X 或 Linux 下,下面两条命令可能会适用:

$ sudo easy_install virtualenv

或更好的: 

$ sudo pip install virtualenv

上述的命令会在你的系统中安装 virtualenv。它甚至可能会存在于包管理器中,  Ubuntu下,可以尝试:

$ sudo apt-get install python-virtualenv

Windows下,可以尝试:

pip install virtualenv

virtualenv 安装完毕后,你可以立即打开 shell 然后创建你自己的环境。通常创建一个项目文件夹,并在其下创建一个 venv 文件夹 。【Mac或Linux下】

$ mkdir myproject
$ cd myproject
$ virtualenv venv
New python executable in venv/bin/python
Installing distribute............done.

现在,无论何时你想在某个项目上工作,只需要激活相应的环境。在 OS X 和 Linux 上,执行如下操作:

$ . venv/bin/activate

下面的操作适用 Windows:

$ venv\scripts\activate

 

【Flask】安装及入门_第1张图片

 

无论通过哪种方式,你现在应该已经激活了 virtualenv(注意你的 shell 提示符显示的是当前活动的环境)。

现在你只需要键入以下的命令来激活 virtualenv 中的 Flask:

$ pip install Flask

几秒钟后,一切都搞定了。

Windows下,这些命令行将会下载以及安装我们将会在我们的应用程序中使用的所有的包。

pip install flask
pip install flask-login
pip install flask-openid
pip install flask-mail
pip install flask-sqlalchemy
pip install sqlalchemy-migrate
pip install flask-whooshalchemy
pip install flask-wtf
pip install flask-babel
pip install guess_language
pip install flipflop
pip install coverage

二、Flask入门

2.1 应用

代码:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

运行:

【Flask】安装及入门_第2张图片

打开http://127.0.0.1:5000/

【Flask】安装及入门_第3张图片

这段代码做了这么几件事:

  1. 首先,我们导入了 Flask 类。这个类的实例将会是我们的 WSGI 应用程序。
  2. 接下来,我们创建一个该类的实例,第一个参数是应用模块或者包的名称。 如果你使用单一的模块(如本例),你应该使用 __name__ ,因为模块的名称将会因其作为单独应用启动还是作为模块导入而有不同( 也即是 '__main__' 或实际的导入名)。这是必须的,这样 Flask 才知道到哪去找模板、静态文件等等。详情见 Flask的文档。
  3. 然后,我们使用 route() 装饰器告诉 Flask 什么样的URL 能触发我们的函数。
  4. 这个函数的名字也在生成 URL 时被特定的函数采用,这个函数返回我们想要显示在用户浏览器中的信息。
  5. 最后我们用 run() 函数来让应用运行在本地服务器上。 其中 if __name__ =='__main__': 确保服务器只会在该脚本被 Python 解释器直接执行的时候才会运行,而不是作为模块导入的时候。

欲关闭服务器,按 Ctrl+C。

2.2 调试模式

虽然 run() 方法适用于启动本地的开发服务器,但是你每次修改代码后都要手动重启它。这样并不够优雅,而且 Flask 可以做到更好。如果你启用了调试支持,服务器会在代码修改后自动重新载入,并在发生错误时提供一个相当有用的调试器。

有两种途径来启用调试模式。一种是直接在应用对象上设置:

app.debug = True
app.run()

另一种是作为 run 方法的一个参数传入:

app.run(debug=True)

两种方法的效果完全相同。

注意:尽管交互式调试器在允许 fork 的环境中无法正常使用(也即在生产服务器上正常使用几乎是不可能的),但它依然允许执行任意代码。这使它成为一个巨大的安全隐患,因此它 绝对不能用于生产环境 。

这里说明下,为什么有下面的Hello World的Web程序呢? 在工程项目中,通常都有层次和结构。给人更加清晰的感觉。

三、Flask中的Hello World

3.1 第一个Web程序结构

Web程序的结构如下:

【Flask】安装及入门_第4张图片

我们的应用程序包是放置于 app 文件夹中。子文件夹 static 是我们存放静态文件像图片,JS文件以及样式文件。子文件夹 templates 是存放模板文件的。

__init__.py

from flask import Flask

app = Flask(__name__)

from app import views

上面的脚本简单地创建应用对象,接着导入视图模块,该模块在下一段代码中。

视图是响应来自网页浏览器的请求的处理器。在 Flask 中,视图是编写成 Python 函数。每一个视图函数是映射到一个或多个请求的 URL。

views.py

from app import app


@app.route('/')
@app.route('/index')
def index():
    return "Hello, World!"

这个视图是非常简单,它只是返回一个字符串,在客户端的网页浏览器上显示。两个 route 装饰器创建了从网址 / 以及 /index 到这个函数的映射。

能够完整工作的 Web 应用程序的最后一步是创建一个脚本,启动我们的应用程序的开发 Web 服务器。让我们称这个脚本为 run.py,并把它置于根目录(也就是这里的microblog目录下):

run.py

#!flask/bin/python
from app import app
app.run(debug = True)

这个脚本简单地从我们的 app 包中导入 app 变量并且调用它的 run 方法来启动服务器。请记住 app 变量中含有我们在之前创建的 Flask 实例

在Windows下,将flask/scripts路径复制到环境变量Path中后,执行:

python  F:\pycodes\microblog\run.py

在服务器初始化后,它将会监听 5000 端口等待着连接。现在打开你的网页浏览器输入如下 URL:

http://localhost:5000或者http://localhost:5000/index

你看清楚了路由映射是如何工作的吗?第一个 URL 映射到 /,而第二个 URL 映射到 /index。这两个路由都关联到我们的视图函数,因此它们的作用是一样的。如果你输入其它的网址,你将会获得一个错误,因为只有这两个 URL 映射到视图函数

你可以通过 Ctrl-C 来终止服务器。

3.2 模板

在 Python 中生成 HTML 并不好玩,实际上是相当繁琐的,因为你必须自行做好 HTML 转义以保持应用程序的安全。由于这个原因,Flask 自动为你配置好 Jinja2 模版

3.2.1 为什么我们需要模板

让我们来考虑下我们该如何扩充我们这个小的应用程序。

我们希望我们的微博应用程序的主页上有一个欢迎登录用户的标题,这是这种类型的应用程序的一个“标配”。忽略本应用程序暂未有用户的事实,我会在后面的章节引入用户的概念。

输出一个漂亮的大标题的一个容易的选择就是改变我们的视图功能,输出 HTML,也许像这个样子:

from app import app

@app.route('/')
@app.route('/index')
def index():
    user = { 'nickname': 'Miguel' } # fake user
    return '''

  
    Home Page
  
  
    

Hello, ''' + user['nickname'] + '''

'''

运行看看网页浏览器上的显示情况。

我们暂时还不支持用户,所以暂时使用占位符的用户对象,有时也被称为假冒或模仿的对象。这样让我们可以集中关注应用程序的某一方面,而不用花心思在暂未完成的部分上。

我希望你同意我的说法,上面的解决方案是非常难看!如果我们需要返回一个含有大量动态内容的大型以及复杂的 HTML 页面的话,代码将会有多么复杂啊!如果你需要改变你的网站布局,在一个大的应用程序,该应用程序有几十个视图,每一个直接返回HTML?这显然​​不是一个可扩展的选择。

3.2.2模板从天而降

如果你能够保持你的应用程序与网页的布局或者界面逻辑上是分开的,这样不是显得更加容易组织?难道你不觉得是这样吗?你甚至可以聘请一个网页设计师来设计一个杀手级的网页而你专注于 Python 编码。模板可以帮助实现这种分离。

让我们编写第一个我们的模板(文件 app/templates/index.html):


  
    {{title}} - microblog
  
  
      

Hello, {{user.nickname}}!

正如你在上面看到,我们只是写了一个大部分标准的HTML页面,唯一的区别是有一些动态内容的在 {{ … }} 中。

现在看看怎样在我们的视图函数(文件 app/views.py)中使用这些模板:

from flask import render_template
from app import app

@app.route('/')
@app.route('/index')
def index():
    user = { 'nickname': 'Miguel' } # fake user
    return render_template("index.html",
        title = 'Home',
        user = user)

试着运行下应用程序看看模板是如何工作的。一旦在你的网页浏览器上呈现该网页,你可以浏览下 HTML 源代码,与原始的模板内容对比下差别。

为了渲染模板,我们必须从 Flask 框架中导入一个名为 render_template 的新函数。此函数需要传入模板名以及一些模板变量列表,返回一个所有变量被替换的渲染的模板。

在内部,render_template 调用了 Jinja2 模板引擎,Jinja2 模板引擎是 Flask 框架的一部分。Jinja2 会把模板参数提供的相应的值替换了 {{…}}块。

3.2.3 模板中控制语句

Jinja2 模板同样支持控制语句,像在 {%…%} 块中。让我们在我们的模板中添加一个 if 声明(文件 app/templates/index.html):


  
    {% if title %}
    {{title}} - microblog
    {% else %}
    Welcome to microblog
    {% endif %}
  
  
      

Hello, {{user.nickname}}!

现在我们的模板变得更加智能了。如果视图函数忘记输入页面标题的参数,不会触发异常反而会出现我们自己提供的标题。放心地去掉视图函数中 render_template 的调用中的 title 参数,看看 if 语句是如何工作的!

3.2.4 模板中的循环语句

在我们 microblog 应用程序中,登录的用户想要在首页展示他的或者她的联系人列表中用户最近的文章,因此让我们看看如何才能做到。

首先我们先创建一些用户以及他们的文章用来展示(文件 app/views.py):

def index():
    user = { 'nickname': 'Miguel' } # fake user
    posts = [ # fake array of posts
        {
            'author': { 'nickname': 'John' },
            'body': 'Beautiful day in Portland!'
        },
        {
            'author': { 'nickname': 'Susan' },
            'body': 'The Avengers movie was so cool!'
        }
    ]
    return render_template("index.html",
        title = 'Home',
        user = user,
        posts = posts)

为了表示用户的文章,我们使用了列表,其中每一个元素包含 author 和 body 字段。当我们使用真正的数据库的时候,我们会保留这些字段的名称,因此我们在设计以及测试模板的时候尽管使用的是假冒的对象,但不必担心迁移到数据库上更新模板。

在模板这一方面,我们必须解决一个新问题。列表中可能有许多元素,多少篇文章被展示将取决于视图函数。模板不会假设有多少文章,因此它必须准备渲染视图传送的文章数量。

因此让我们来看看怎么使用 for 来做到这一点(文件 app/templates/index.html):


  
    {% if title %}
    {{title}} - microblog
    {% else %}
    microblog
    {% endif %}
  
  
    

Hi, {{user.nickname}}!

{% for post in posts %}

{{post.author.nickname}} says: {{post.body}}

{% endfor %}

简单吧?试试吧,确保给予足够的文章列表。

3.2.5 模板继承

在我们的 microblog 应用程序中,在页面的顶部需要一个导航栏。在导航栏里面有编辑账号,登出等等的链接。

我们可以在 index.html 模板中添加一个导航栏,但是随着应用的扩展,越来越多的模板需要这个导航栏,我们需要在每一个模板中复制这个导航栏。然而你必须要保证每一个导航栏都要同步,如果你有大量的模板,这需要花费很大的力气。

相反,我们可以利用 Jinja2 的模板继承的特点,这允许我们把所有模板公共的部分移除出页面的布局,接着把它们放在一个基础模板中,所有使用它的模板可以导入该基础模板。

所以让我们定义一个基础模板,该模板包含导航栏以及上面谈论的标题(文件 app/templates/base.html):


  
    {% if title %}
    {{title}} - microblog
    {% else %}
    microblog
    {% endif %}
  
  
    
Microblog: Home

{% block content %}{% endblock %}

在这个模板中,我们使用 block 控制语句来定义派生模板可以插入的地方。块被赋予唯一的名字。

接着现在剩下的就是修改我们的 index.html 模板继承自 base.html (文件 app/templates/index.html):

{% extends "base.html" %}
{% block content %}

Hi, {{user.nickname}}!

{% for post in posts %}

{{post.author.nickname}} says: {{post.body}}

{% endfor %} {% endblock %}

 

 

参考:

flask mega-tutorial:http://www.pythondoc.com/flask-mega-tutorial/

中文文档:http://docs.jinkan.org/docs/flask/

官方文档:http://flask.pocoo.org/docs/1.0/

你可能感兴趣的:(Flask,WEB)