从零开始用 Flask 搭建一个网站(一) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
jpush
V2EX    Python

从零开始用 Flask 搭建一个网站(一)

  •  
  •   jpush
    jpush 2017-04-10 14:23:03 +08:00 9740 次点击
    这是一个创建于 3188 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    笔者之前未接触过 Python ,只是略懂一点前端,所以说从零开始也相差无几吧。Flask 是一个轻量级的基于 Python 的框架,但是扩展性非常良好( Github 上 22000 多个 star 就知道群众的选择不无道理),其他的这里就不多提了,下面就开始我们的网站搭建之路。

    开始

    环境搭建

    首先需要准备 Python 开发环境,这里推荐使用 pyenv 来安装和管理 Python 。笔者使用的是 Mac OSX (自带 Python 2.6 ),直接使用如下命令安装 pyenv :

    brew install pyenv 

    之后要升级 pyenv 的话就用:

    brew upgrade pyenv 

    安装完以后,需要配置环境变量,如果使用 zsh ,需要在 ~/.zshrc 加入以下代码:

    export PYENV_ROOT="$HOME/.pyenv" export PATH="$PYENV_ROOT/bin:$PATH" export PATH=$PATH:/sbin/ eval "$(pyenv init -)" 

    如果使用 bash ,在 ~/.bash_profile 中加入即可。保存后重启终端即可。 如果要安装 Python 3.5.2 ,可以用

    pyenv install 3.5.2 

    查看安装的 Python 版本:

    pyenv versions 

    切换局部 Python 环境(这里一般指在 Application 文件夹下切换环境)

    pyenv local 3.5.2 

    关于其他更多命令,可以参考 Command.md

    使用 IDE

    这里笔者推荐使用 PyCharm 来进行 python 项目开发。下载安装后(这里笔者下载的是 Professional 版本),新建一个 Flask 项目,然后指定目录、 python 环境:

    完成后点击 Create ,这样就创建了一个 Flask 项目,如果没有安装 Flask , PyCharm 会自动下载安装。如果想使用 virtualenv ,可以参考下一个步骤。

    使用虚拟环境

    使用虚拟环境可以方便地安装 Flask 而且可以在系统的 Python 解释器中避免包的混乱和版本的冲突。 Python 3.3 以后原生支持虚拟环境,命令为 pyvenv 。可以使用如下命令创建虚拟环境(进入刚才创建的 Flask 项目文件夹):

    pyvenv venv 

    如果使用 Python 2.7 或者以下版本,可以使用第三方工具 virtualenv 创建虚拟环境:

    sudo easy_install virtualenv 

    以上命令就可以安装 virtualenv (如果没有安装 easy_install ,需要手动安装,而 pyvenv 已经自带 pip 和 easy_install )。下一步使用 virtualenv 命令在文件夹中创建 Python 虚拟环境:

    virtualenv venv 

    完成后,会在 Flask 项目下生成 venv 文件夹。在使用虚拟环境之前,要先使用( pyvenv 和 virtualenv 创建的虚拟环境是一样的,因此以下命令均可使用):

    source venv/bin/activate 

    来激活,如果要退出虚拟环境,可以使用:

    deactivate 

    创建的虚拟环境会自动安装 pip 和 easy_install ,接下来可以使用:

    pip install flask 

    接下来就可以在 Flask 中开始自由地遨(入)游(坑)啦!

    Flask 程序结构

    在介绍 Flask 的程序结构之前,先来看看标准 Flask 项目的项目结构(笔者以为从宏观到微观的方式可以更快的了解一个东西)。使用 PyCharm 新建 Flask 项目后,项目结构如下图所示:

    只有三个文件夹( venv 文件夹已经用命令行生成了)和一个简单的入口类,接下来要把项目结构改造成标准的 Flask 项目结构:

    Flask 项目有 4 个顶级文件夹:

    • app (本例中是 jbox ) Flask 程序保存在此文件夹中
    • migrations 包含数据库迁移脚本(安装了 flask-migrate 后自动生成)
    • tests 单元测试放在此文件夹下
    • venv Python 虚拟环境

    同时还有一些文件:

    • requirements.txt 列出了所有的依赖包,以便于在其他电脑中重新生成相同的环境
    • config.py 存储配置
    • manage.py 启动程序或者其他任务
    • gun.conf Gunicorn 配置文件

    虽然新建的 Flask Project 已经可以运行,但是我们还是要按照标准的 Flask 程序来改造项目结构。下面我们就来改造一下 TestProject 。 在命令行中依次使用以下命令来安装 Flask 扩展:

    pip install flask-script pip install flask-sqlalchemy pip install flask-migrate 

    flask-script 可以自定义命令行命令,用来启动程序或其它任务; flask-sqlalchemy 用来管理数据库的工具,支持多种数据库后台; flask-migrate 是数据库迁移工具,该工具命令集成到 flask-script 中,方便在命令行中进行操作。

    然后创建 config.py 文件,内容如下:

    config.py

    import os basedir = os.path.abspath(os.path.dirname(__file__)) class config: SECRET_KEY = os.environ.get('SECRET_KEY') or 'this is a secret string' SQLALCHEMY_TRACK_MODIFICATIOnS= True @staticmethod def init_app(app): pass class DevelopmentConfig(config): DEBUG = True SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \ 'sqlite:///' + os.path.join(baedir, 'dev') class TestingConfig(config): TESTING = True SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'test') class ProductionConfig(config): SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'data.sqlite') cOnfig= { 'development': DevelopmentConfig, 'testing': TestingConfig, 'production': ProductionConfig, 'default': DevelopmentConfig } 

    config 顾名思义,保存了一些配置变量。 SQLALCHEMY_DATABASE_URI 变量在不同的配置中被赋予了不同的值,这样就可以在不同的环境中切换数据库。如果是远程数据库则从环境变量中读取 URL ,否则在本地路径中创建。

    接下来创建一个 app 文件夹,并在此文件夹中创建一个 __init__.py 文件( init 前后都有两个下划线):

    app/__init__.py

    from flask import Flask from flask_sqlalchemy import SQLAlchemy from config import config db = SQLAlchemy() def create_app(config_name): app = Flask(__name__) app.config.from_object(config[config_name]) config[config_name].init_app(app) db.init_app(app) //此处缺省了部分代码,后面会加上 return app 

    create_app() 就是程序的工厂函数,参数就是配置类的名字,即 config.py ,其中保存的配置可以使用 from_object() 方法导入。

    接下来要解释两个重要的概念路由和视图函数。客户端把请求发给 Web 服务器, Web 服务器再把请求发给 Flask 程序实例, Flask 程序实例需要知道每个 URL 请求要运行哪些代码,所以保存了一个 URL 到 Python 函数的映射关系。处理 URL 和函数之间关系的程序称为路由,这个函数称为视图函数。例如:

    @app.route('/') def index(): return '<h1>Hello World</h1>' 

    这里使用 app.route 修饰器来定义路由, app 指 Flask 程序实例对象,后面可以看到使用蓝本管理路由后,由蓝本实例对象来取代 app 。 Flask 使用蓝本来定义路由,在蓝本中定义的路由处于休眠状态,直到蓝本注册到程序上后,路由真正成为程序的一部分。蓝本通常使用结构化的方式保存在包的多个模块中。接下来在 app 文件夹下创建一个子文件夹 main ,并在 main 中创建 __init__.py (如果使用 PyCharm ,这里有个快捷方式,右键点击 app 文件夹,在菜单中选择 new -> Python Package ,在弹出的对话框中填写包名然后确认即可):

    app/main/__ init__.py

    from flask import Blueprint //实例化 Blueprint 类,两个参数分别为蓝本的名字和蓝本所在包或模块,第二个通常填 __name__ 即可 main = Blueprint('main', __name__) from . import views, errors 

    最后引用了两个文件,之所以写在最后是因为避免循环导入依赖,因为接下来在 main 文件夹下 创建的 views.pyerrors.py 都要导入蓝本 main 。

    app/main/views.py

    from flask import render_template //导入蓝本 main from . import main @main.route('/') def index(): return render_template('index.html') 

    在之前路由的概念解释中, index 函数直接返回了 HTML 字符串(通常不这么做),这里则使用了 render_templete() 函数来渲染 index.html ,并返回。 Flask 使用了 Jinja2 引擎来渲染模板,模板文件都放在 templates 文件夹下,并且只能命名为 templates ,否则 Jinja2 会抛出 TemplageNotFound 异常。由于我们的 app 是一个 Python Package (在目录中包含 init.py 默认成为 Python Package ),所以需要将 templates 放在 app 目录下。在 app 下 中创建名为 templates 的文件夹,在 PyCharm 中右键点击该文件夹,然后选择 Make Directory As -> Template Folder ,如图:

    接下来在 templates 下新建一个 index.html 和 404.html 模板:

    app/templates/index.html

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <h1>Hello World</h1> </body> </html> 

    app/templates/404.html

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Not Found</title> </head> <body> <h1>Can't find request page!</h1> </body> </html> 

    之后会讲解模板的具体用法,现在接着来定义 errors.py:

    app/main/errors.py

    from flask import render_template from . import main @main.app_errorhandler(404) def page_not_found(e): return render_template('404.html'), 404 

    上面的步骤是让程序的路由保存在 views.py 中,而错误处理交给 errors.py ,这两个模块已经和蓝本 main 关联起来了(在蓝本中导入了这两个模块),现在需要在工厂函数中注册蓝本 main 。将如下代码加入到上面缺省代码中即可:

    app/__init__.py

    def create_app(config_name): #... from .main import main as main_blueprint app.register_blueprint(main_blueprint) return app 

    最后两个步骤是创建 requirements.txt 以及启动脚本 manage.py 。程序中必须包含一个 requirements.txt 文件,用于记录所有的依赖包和版本号,便于在其它电脑上创建相同的开发环境。直接在终端使用如下命令即可创建 requirements.txt 文件:

    pipfreeze>requirements.txt 

    以后安装了新的依赖包或者升级版本后,重新执行该命令即可更新 requirements.txt 文件。如果要手动添加也可以,在 PyCharm 中用 Command + , 唤出 Preferences 对话框,然后选择 Project -> Project Interpreter 即可查看所有的依赖包及其版本号(还有最新版本号提示),如图:

    如果要在另一台电脑上创建这个虚拟环境的完全副本,运行以下命令即可:

    pip install -r requirements.txt 

    最后创建启动脚本 manage.py

    manage.py

    import os from app import create_app, db from flask_script import Manager, Shell from flask_migrate import Migrate, MigrateCommand app = create_app(os.getenv('FLASK_CONFIG') or 'default') manager = Manager(app) migrate = Migrate(app, db) def make_shell_context(): return dict(app=app, db=db) manager.add_command("shell",Shell(make_cOntext=make_shell_context)) manager.add_command('db', MigrateCommand) if __name__ == '__main__': manager.run() 

    这个脚本首先创建程序,然后增加了两个命令: shell 和 db ,我们之后可以在命令行中直接使用。

    到此为止,我们的目录结构如下:

    运行

    现在就来启动我们的程序,在命令行中进入 TestProject 目录,然后执行如下命令即可运行:

    python manage.py runserver 

    命令行运行截图如下:

    Flask 默认的本机地址为: http://127.0.0.1:5000/ ,现在用浏览器打开这个地址,应该可以看到如下页面:

    到这一步,我们的第一个 Flask 程序已经完成了!虽然还没有建立数据库,页面也非常糟糕,但是之后我们会一步步进行完善! 本文参考书籍 Flask Web 开发:基于 Python 的 Web 应用开发实战(作者: Miguel Grinberg)

    作者: KenChoi - 极光( JPush 为极光团队账号,欢迎关注)

    原文:从零开始用 Flask 搭建一个网站(一)

    知乎专栏:极光日报

    11 条回复    2018-05-14 12:04:50 +08:00
    tr>
    v166ex
        1
    v166ex  
       2017-04-10 15:09:41 +08:00
    赞一个,是最基础的也是最重要的
    wisperguo
        2
    wisperguo  
       2017-04-10 15:34:28 +08:00
    给作者点赞, 去年瞎摸做完一个网站。 感觉 Flask 效果不太好, 太繁琐。 不过是入门的好工具,够简单。
    yanzixuan
        3
    yanzixuan  
       2017-04-10 17:54:27 +08:00
    其实 pycharm 里面就可以创建 VIRTUALENV 。
    自己搭的 VIRTUALEnv 在 pyharm 无法高亮和自动补全。感觉有点诡异。
    难道使用的姿势不对?
    realwangyibo
        4
    realwangyibo  
       2017-04-10 21:19:05 +08:00
    @yanzixuan 需要要在 Project Interpreter 识别出虚拟环境的解释器,才可以实现你提到的功能
    hzwjz
        5
    hzwjz  
       2017-04-10 21:25:06 +08:00
    这不就是那本狗书的例子吗?
    wingyiu
        6
    wingyiu  
       2017-04-11 11:38:32 +08:00
    这种文章一搜一大把 有必要发这么
    eason622
        7
    eason622  
       2017-04-11 15:17:46 +08:00
    目前在看狗书,总有一点奇怪的小问题,正好需要这种类似他人的笔记
    jpush
        8
    jpush  
    OP
       2017-04-11 17:13:45 +08:00
    @wingyiu 因为你比较厉害 所以你并不是这篇文章的受众
    akiyamamio
        9
    akiyamamio  
       2017-04-12 14:39:47 +08:00
    @wingyiu 看标题我就觉得敢在 V2EX 写基础教程的,那可是真正的猛士,敢于直面莫名其妙的喷子
    geek123
        10
    geek123  
       2017-08-31 15:02:58 +08:00
    robinlovemaggie
        11
    robinlovemaggie  
       2018-05-14 12:04:50 +08:00
    看了一遍,不仅要说一下转载文章的内容有两处错误:
    1. pyhhon 的注释符号不是 ‘//’
    2. config.py 文件中,子类继承的分类 config 名字有误。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1234 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 16:54 PVG 00:54 LAX 08:54 JFK 11:54
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86