《Flask Web开发:基于Python的Web应用开发实战》
虽然简单的网站(Flask+Python+SAE)已经上线,但只是入门。开发大型网站,系统地学习一遍还是有必要的。
20161018: 实际应用网站上线,实现天涯VIP功能:http://tianya.heroku.com
2016-6-8
书上介绍了 virtualenv,每个venv都会拷贝一份packages到项目 /venv目录。
[plain] view plain copy
比较了一下conda管理环境,可能conda更胜一筹:点击打开链接
或者用 virtualenvwrapper: 点击打开链接
[plain] view plain copy
.gitignore:指定哪些文件或目录不作同步,比如 ./venv/,*.pyc,数据库文件.sqlite3, .mysql
推荐IDE: PyCharm 2016.1
导入已有的virtualenv: File -> Setting -> Project Interprater -> 选择项目目录下的/venv/Python
特点:
-> new Flask Project
-> jump between View funcion and Templates
-> Git
初始化:
[python] view plain copy
Flask类的构造函数只有一个必须指定的参数,即程序主模块或包的名字。在大多数程序中,Python的__name__变量就是所需的值。Flask用这个参数决定程序的根目录,以便稍后能够找到相对于程序根目录的资源文件位置
路由 (route)和视图函数 (view function):
定义路由的最简便方式,是使用程序实例提供的app.route修饰器,把修饰的函数注册为路由
[python] view plain copy
修饰器是Python语言的标准特性,可以使用不同的方式修改函数的行为。惯常用法是使用修饰器把函数注册为事件的处理程序。
动态路由:地址中可以包含可变部分,Flask支持在路由中使用int、float和path类型。path类型也是字符串,但不把斜线视作分隔符
[python] view plain copy
默认端口是5000,可以改成其它的(flask_script.Manager也有此功能)
python manage.py runserver -p 7777
# 有些端口不能用,查询已占用的端口:netstat -ano;netstat -aon|findstr "6000";tasklist|findstr "
[python] view plain copy
请求-响应循环
Context 上下文全局变量:
URL映射是URL和视图函数之间的对应关系。Flask使用app.route修饰器或者非修饰器形式的app.add_url_rule()生成映射。
[python] view plain copy
HEAD、Options、GET是请求方法,由路由进行处理。Flask为每个路由都指定了请求方法,这样不同的请求方法发送到相同的URL上时,会使用不同的视图函数进行处理。HEAD和OPTIONS方法由Flask自动处理
请求 Hook: 在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量g
响应(视图函数返回)
[python] view plain copy
Flask扩展
原书更正: Importing flask.ext.script is deprecated, use flask_script instead.
业务逻辑和表现逻辑 要分开
按功能分(模板不需要重用时),或按Division分(大部分模板需要重用时)
Jinja2模板引擎
模板是一个包含响应文本的文件,其中包含用占位变量{{...}}表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为渲染。
[python] view plain copy
模板变量
Jinja2能识别所有类型的变量,甚至是一些复杂的类型,例如列表、字典和对象
[html] view plain copy
可以使用过滤器修改变量。千万别在不可信的值上使用safe过滤器,例如用户在表单中输入的文本
[html] view plain copy
完整的过滤器列表
控制结构{%...%},可用来改变模板的渲染流程 if, for, macro, import, include
需要在多处重复使用的模板代码片段可以写入单独的文件,再包含 {%include 'common.html' %} 在所有模板中
另一种重复使用代码的强大方式是模板继承,block标签定义的元素可在衍生模板中修改
[html] view plain copy
extends指令声明这个模板衍生自base.html。在extends指令之后,基模板中的3个块被重新定义,模板引擎会将其插入适当的位置。注意新定义的head块,在基模板中其内容不是空的,所以使用super()获取原来的内容(向已经有内容的块中添加新内容)。
[html] view plain copy
使用Flask-Bootstrap
Bootstrap是客户端框架,因此不会直接涉及服务器。服务器需要做的只是提供引用了Bootstrap层 叠样式表(CSS)和JavaScript文 件的HTML响 应,并在HTML、CSS和JavaScript代码中实例化所需组件。这些操作最理想的执行场所就是模板。
Flask-Bootstrap基模板中定义的块:doc, head, title, styles, body, navbar, content, scripts
Bootstrap官方文档
CDN本地加速:
修改 Base.html,引用本地的css 文件,里面元素跟Bootstrap 重名的,则会覆盖官方里相同元素
[html] view plain copy
2016-10-20: 以上本地加速证明是有误的!会重复下载本地和官方Bootstrap 的 css/js
解决:
/app/__init__.py
from flask_bootstrap import Bootstrap, WebCDN, ConditionalCDN, BOOTSTRAP_VERSION, JQUERY_VERSION, HTML5SHIV_VERSION, RESPONDJS_VERSION
def create_app(config_name):
[python] view plain copy
另外:本地加速 moment.js
这个文件也在国外服务器,访问很慢,而且 size=160KB
/app/templates/base.html
{% block scripts %}
{{ super() }}
{{ moment.include_moment(local_js="/static/moment-with-locales.min.js") }}
{{ moment.lang('zh-CN') }}
{% endblock %}
需要单独下载 https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.3/moment-with-locales.min.js 到本地目录 /app/static/
自定义错误页面
[python] view plain copy
url_for() 链接辅助函数
使用url_for()生成动态地址时,将动态部分作为关键字参数传入。例如,
url_for('user', name='john', _external=True)的返回结果是http://localhost:5000/user/john
使用Flask-Moment本地化日期和时间。查阅文档
[html] view plain copy
app.config字典可用来存储框架、扩展和程序本身的配置变量。使用标准的字典句法就能把配置值添加到app.config对象中。这个对象还提供了一些方法,可以从文件或环境中导入配置值。
Form基类由Flask-WTF扩展定义,所以从flask.ext.wtf中导入。字段和验证函数 可以直接从WTForms包中导入。
[python] view plain copy
WTForms支持的HTML标准字段:StringField,TextAreaField,PasswordField。。。
WTForms内建的验证函数:Email,DataRequired...
Placeholder提示:
[python] view plain copy
重定向和用户会话
刷新页面后会再次提交表单。大多数情况下,这并不是理想的处理方式。
很多用户都不理解浏览器发出的这个警告。 基于这个原因,最好别让 Web 程序把 POST 请求作为浏览器发送的最后一个请求。
这个技巧称为Post/重定向/Get模式。
[python] view plain copy
使用get()获取字典中键对应的值以避免未找到键的异常情况,因为对于不存在的键,get()会返回默认值None。
Flash消息
仅调用flash()函数并不能把消息显示出来,程序使用的模板要渲染这些消息。最好在base.html 中渲染Flash消息,因为这样所有页面都能使用这些消息。Flask把get_flashed_messages()函数开放给模板,用来获取并渲染消息
2016-6-9
使用SQL还是NoSQL
SQL 数据库擅于用高效且紧凑的形式存储结构化数据。这种数据库需要花费大量精力保证数据的一致性。NoSQL 数据库放宽了对这种一致性的要求,从而获得性能上的优势。
MySQL Q&A:
安装MySQL in Windows 报错:需要预先把Windows Defender 打开,或者configure mysql server时,不要勾选“Windows Firewall”
可能要先安装:Microsoft Visual C++ Compiler for Python 2.7
本地安装MySQLdb: pip install mysql-python
Window7 64位下安装可能还会报 cl.exe错
workaround: 先conda install mysql-python,再手动复制以下目录及文件到 venv\Lib\Site-packages下:
Anaconda2\Lib\site-packages\MySQLdb
Anaconda2\Lib\site-packages\MySQL_python-1.2.5.dist-info
Anaconda2\Lib\site-packages\_mysql*
MySQL创建connection之后,还需要创建“schema” --> 对应SQLAlchemy里的“database”
MySQLdb 中文乱码的处理:
conn = MySQLdb.connect(host='localhost', user='root', passwd='XXX', db='app_englishgo', charset = 'utf8')
显示:title.encode('gbk')
接收输入:unicode(request.form['title'])
SQLAlchemy 和MongoEngine:数据库抽象层代码包(ORM、ODM),你可以使用这些抽象包直接处理高等级的 Python 对象,而不用处理如表、文档或查询语言此类的数据库实体。
使用Flask-SQLAlchemy管理数据库
MySQL mysql://username:password@hostname:port/database
SQLite(Windows) sqlite:///c:/absolute/path/to/database
Relationship 关系型数据库
[python] view plain copy
SQLAlchemy 完整的命令、过滤器、查询执行 列表参见 SQLAlchemy 文档
SQLAlchemy engine设置编码,防止中文乱码:
[python] view plain copy
[python] view plain copy
集成python shell
每次启动 shell 会话都要导入数据库实例和模型。为避免重复导入,我们可以做些配置,让 Flask-Script 的 shell 命令自动导入特定的对象。为 shell 命令注册一个 make_context 回调函数
新数据库迁移 flask-migrate
由于模型中经常会新加一行或几行column (比如用来保存账户的确认状态),此时要修改 models.py,并执行一次新数据库迁移
MySQL Workbench 自动产生EER,可以清楚地看到各个表格之间关系:一对多 Foreign_Key、Index等
1) config.py:
[python] view plain copy
2) python manage.py deploy
3) mysql Workbench: Database -> Reverse Engineer -> 选择 connection -> database -> 一路 Next
使用Flask-Mail提供电子邮件支持
[python] view plain copy
千万不要把账户密令直接写入脚本,特别是当你计划开源自己的作品时。让脚本从本机环境中导入敏感信息Windows 用户可按照下面的方式设定环境变量:
[plain] view plain copy
所有的在cmd命令行下对环境变量的修改只对当前窗口有效,不是永久性的修改。也就是说当关闭此cmd命令行窗口后,将不再起作用。永久性修改环境变量的方法有两种:一种是直接修改注册表(overkill python script),另一种是通过我的电脑-〉属性-〉高级,来设置系统的环境变量
异步发送电子邮件
为了避免处理请求过程中不必要的延迟,我们可以把发送电子邮件的函数移到后台线程(Threading)中
很多 Flask 扩展都假设已经存在激活的程序上下文和请求上下文。Flask-Mail 中的 send() 函数使用 current_app ,因此必须激活程序上下文。不过,在不同线程中执行 mail.send() 函数时,程序上下文要使用 app.app_context() 人工创建。
项目结构
[plain] view plain copy
requirements.txt 文件,用于记录所有依赖包及其精确的版本号。以便要在另一台电脑上重新生成虚拟环境
创建:(venv) $ pip freeze > requirements.txt
恢复:(venv) $ pip install -r requirements.txt
重组后的程序和单脚本版本使用不同的数据库,可使用如下命令创建数据表或者升级到最新修订版本:(venv) $ python manage.py db upgrade
Flask的认证扩展
Flask-Login:管理已登录用户的用户会话。
Werkzeug:计算密码散列值并进行核对。
itsdangerous:生成并核对加密安全令牌。
创建认证蓝本
对于不同的程序功能,我们要使用不同的蓝本(main, auth),这是保持代码整齐有序的好方法
因为 Flask 认为模板的路径是相对于程序模板文件夹而言的。为避免与 main 蓝本和后续添加的蓝本发生模板命名冲突,可以把蓝本使用的模板保存在单独的文件夹中
使用Flask-Login认证用户
LoginManager 对象的 session_protection 属性可以设为 None 、 'basic' 或 'strong' ,以提供不同的安全等级防止用户会话遭篡改。设为 'strong' 时,Flask-Login 会记录客户端 IP地址和浏览器的用户代理信息,如果发现异动就登出用户。
为了保护路由只让认证用户访问,Flask-Login 提供了一个 login_required 修饰器
current_user 由 Flask-Login 定义,且在视图函数和模板中自动可用
模板中加入用户登录后的信息和提示效果 base.html:
[html] view plain copy
按照第 4 章介绍的“Post/ 重定向 /Get 模式”,Login的 POST 请求最后也做了重定向,不过目标 URL 有两种可能。用户访问未授权的 URL 时会显示登录表单,Flask-Login 会把原地址保存在查询字符串的next参数中,这个参数可从 request.args 字典中读取。如果查询字符串中没有 next 参数,则重定向到首页
app/auth/views.py
[python] view plain copy
用户注册表单 app/auth/forms.py
这个表单使用 WTForms 提供的 Regexp 验证函数,确保 username 字段只包含字母、数字、下划线和点号。
密码要输入两次。此时要验证两个密码字段中的值是否一致,这种验证可使用WTForms 提供的另一验证函数实现,即 EqualTo
如果表单类中定义了以validate_ 开头且后面跟着字段名的方法,这个方法就和常规的验证函数一起调用
发送确认邮件
使用itsdangerous生成确认令牌
[python] view plain copy
对蓝本来说, before_request 钩子只能应用到属于蓝本的请求上。若想在蓝本中使用针对程序全局请求的钩子,必须使用 before_app_request 修饰器
2016-6-10
角色在数据库中的表示
赋予角色
角色验证
2016-6-10
用户资料页面
资料编辑器
用户头像
国内 gravatar.com被墙,改用其它方法:静态jpg头像
目录:c:\git\flasky\app\static\avatar\001.jpg ~ XXX.jpg
base.html:
[html] view plain copy
models.py:
[python] view plain copy
user.html:
[html] view plain copy
_posts.html:
[html] view plain copy
_commments.html:
[html] view plain copy
效果:
扩展TODO:加入性别、用户自选头像。。。
2016-6-12
实现功能,即允许用户阅读、撰写博客文章。本章新技术:重用模板、分页显示长列表以及处理富文本。
生成虚拟信息用于测试,其中功能相对完善的是ForgeryPy
[python] view plain copy
添加分页导航
paginate() 方法的返回值是一个 Pagination 类对象,这个类在 Flask-SQLAlchemy 中定义。这个对象包含很多属性, 用于在模板中生成分页链接
使用Markdown和Flask-PageDown支持富文本文章
• PageDown: 使用JavaScript实现的客户端Markdown到HTML的转换程序。
• Flask-PageDown: 为Flask包装的PageDown,把PageDown集成到Flask-WTF表单中。
• Markdown: 使用Python实现的服务器端Markdown到HTML的转换程序。
• Bleach: 使用Python实现的HTML清理器。
博客文章的固定链接
博客文章编辑器
2016-6-12
再论数据库关系
一对多关系:是最常用的关系类型,它把一个记录和一组相关的记录联系在一起。实现这种关系时,要在“多”这一侧加入一个外键,指向“一”这一侧联接的记录。
多对多关系: 这种问题的解决方法是添加第三张表, 这个表称为关联表。多对多关系可以分解成原表和关联表之间的两个一对多关系
若想显示所关注用户发布的所有文章,第一步显然先要获取这些用户,然后获取各用户的文章,再按一定顺序排列,写入单独列表。可是这种方式的伸缩性不好,随着数据库不断变大,生成这个列表的工作量也不断增长,而且分页等操作也无法高效率完成。获取博客文章的高效方式是只用一次查询。
完成这个操作的数据库操作称为联结。联结操作用到两个或更多的数据表, 在其中查找满足指定条件的记录组合, 再把记录组合插入一个临时表中,这个临时表就是联结查询的结果。
创建函数更新数据库这一技术经常用来更新已部署的程序,因为运行脚本更新比手动更新数据库更少出错。
评论属于某篇博客文章,因此定义了一个从posts表到comments表的一对多关系。使用这个关系可以获取某篇特定博客文章的评论列表。
comments 表还和 users 表之间有一对多关系。通过这个关系可以获取用户发表的所有评论,还能间接知道用户发表了多少篇评论
管理评论,我们要在导航条中添加一个链接,具有权限的用户才能看到。
2016-6-12
资源就是一切
资源是REST架构方式的核心概念。在REST架构中, 资源是程序中你要着重关注的事物。例如,在博客程序中,用户、博客文章和评论都是资源。
创建新的Shell命令 deploy:
[python] view plain copy
Flask自带的开发Web服务器表现很差,因为它不是为生产环境设计的服务器。有两个可以在生产环境中使用、性能良好且支持Flask程序的服务器,分别是 Gunicorn 和 uWSGI。
manage:app参数冒号左边的部分表示定义程序的包或者模块,冒号右边的部分表示包中程序实例的名字。注意,Gunicor默认使用端口8000,而Flask默认使用5000。
添加ProxyFix等WSGI中间件的方法是包装WSGI程序。收到请求时,中间件有机会审查环境,在处理请求之前做些修改。不仅Heroku需要使用ProxyFix中间件,任何使用反向代理的部署环境都需要。
架设服务器
在能够托管程序之前,服务器必须完成多项管理任务。
Flask-Cache插件为你提供一组装饰器来实现多种方式的缓存
开发自定义视图装饰器来帮助我们组织自己的代码
自定义的URL转换器将会让你很嗨地玩转URL:https://spacewander.github.io/explore-flask-zh/6-advanced_patterns_for_views_and_routing.html
Write a Tumblelog Application with Flask and MongoEngine
这是MongoDB官方文档中的一个教程,也是学习Flask开发的一个很好案例,尤其适合Flask+mongodb开发的应用场景
The Hitchhiker’s Guide to Python!
这个资料虽然不直接与Flask有关,但对初学者,绝对有学习的价值
GitHub - humiaozuzu/awesome-flask: A curated list of awesome Flask resources and plugins
The Flask Mega-Tutorial, Part I: Hello, World! - miguelgrinberg.com
大多数内容是本书上写的更加 advanced,但以下话题只在“Mega Tutorial”里提到:
一些值得研究的包。
Flask官方扩展网站
PEP 8: 每级缩进使用4个空格。不要使用tab
PEP 257: docstrings""" docstrings """
用了相对形式的import 点标记法:第一个.来表示当前目录,之后的每一个.表示下一个父目录。
from .modelsimport User
https://spacewander.github.io/explore-flask-zh/7-blueprints.html
什么是蓝图?
一个蓝图定义了可用于单个应用的视图,模板,静态文件等等的集合。举个例子,想象一下我们有一个用于管理面板的蓝图。这个蓝图将定义像/admin/login和/admin/dashboard这样的路由的视图。它可能还包括所需的模板和静态文件。你可以把这个蓝图当做你的应用的管理面板,管它是宇航员的交友网站,还是火箭推销员的CRM系统。
蓝图的杀手锏是将你的应用组织成不同的组件。假如我们有一个微博客,我们可能需要有一个蓝图用于网站页面,比如index.html和about.html。然后我们还需要一个用于在登录面板中展示最新消息的蓝图,以及另外一个用于管理员面板的蓝图。站点中每一个独立的区域也可以在代码上隔绝开来。最终你将能够把你的应用依据许多能完成单一任务的小应用组织起来。
Flask.register_blueprint()
注册它。
pip install flask-sqlalchemy
pip install flask-login
...
from flask.ext.bootstrap import Bootstrap
bootstrap = Bootstrap(app)
然后 /template/目录下创建自己的 html,{% extends "bootstrap/base.html" %}
模板:\Lib\site-packages\flask_bootstrap\templates\bootstrap\
Bootstrap 导航栏 自定义配色:
{% block styles %}
{{super()}}
{% endblock %}
其中 style.css 可以包含自定义的 .navbar-kevin {。。。}
配色方案 http://work.smarchal.com/twbscolor/
修改文件:/app/__init__.py
[python] view plain copy
文章标签: pythonwebflaskweb框架
《Flask Web开发:基于Python的Web应用开发实战》
虽然简单的网站(Flask+Python+SAE)已经上线,但只是入门。开发大型网站,系统地学习一遍还是有必要的。
20161018: 实际应用网站上线,实现天涯VIP功能:http://tianya.heroku.com
2016-6-8
书上介绍了 virtualenv,每个venv都会拷贝一份packages到项目 /venv目录。
[plain] view plain copy
比较了一下conda管理环境,可能conda更胜一筹:点击打开链接
或者用 virtualenvwrapper: 点击打开链接
[plain] view plain copy
.gitignore:指定哪些文件或目录不作同步,比如 ./venv/,*.pyc,数据库文件.sqlite3, .mysql
推荐IDE: PyCharm 2016.1
导入已有的virtualenv: File -> Setting -> Project Interprater -> 选择项目目录下的/venv/Python
特点:
-> new Flask Project
-> jump between View funcion and Templates
-> Git
初始化:
[python] view plain copy
Flask类的构造函数只有一个必须指定的参数,即程序主模块或包的名字。在大多数程序中,Python的__name__变量就是所需的值。Flask用这个参数决定程序的根目录,以便稍后能够找到相对于程序根目录的资源文件位置
路由 (route)和视图函数 (view function):
定义路由的最简便方式,是使用程序实例提供的app.route修饰器,把修饰的函数注册为路由
[python] view plain copy
修饰器是Python语言的标准特性,可以使用不同的方式修改函数的行为。惯常用法是使用修饰器把函数注册为事件的处理程序。
动态路由:地址中可以包含可变部分,Flask支持在路由中使用int、float和path类型。path类型也是字符串,但不把斜线视作分隔符
[python] view plain copy
默认端口是5000,可以改成其它的(flask_script.Manager也有此功能)
python manage.py runserver -p 7777
# 有些端口不能用,查询已占用的端口:netstat -ano;netstat -aon|findstr "6000";tasklist|findstr "
[python] view plain copy
请求-响应循环
Context 上下文全局变量:
URL映射是URL和视图函数之间的对应关系。Flask使用app.route修饰器或者非修饰器形式的app.add_url_rule()生成映射。
[python] view plain copy
HEAD、Options、GET是请求方法,由路由进行处理。Flask为每个路由都指定了请求方法,这样不同的请求方法发送到相同的URL上时,会使用不同的视图函数进行处理。HEAD和OPTIONS方法由Flask自动处理
请求 Hook: 在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量g
响应(视图函数返回)
[python] view plain copy
Flask扩展
原书更正: Importing flask.ext.script is deprecated, use flask_script instead.
业务逻辑和表现逻辑 要分开
按功能分(模板不需要重用时),或按Division分(大部分模板需要重用时)
Jinja2模板引擎
模板是一个包含响应文本的文件,其中包含用占位变量{{...}}表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为渲染。
[python] view plain copy
模板变量
Jinja2能识别所有类型的变量,甚至是一些复杂的类型,例如列表、字典和对象
[html] view plain copy
可以使用过滤器修改变量。千万别在不可信的值上使用safe过滤器,例如用户在表单中输入的文本
[html] view plain copy
完整的过滤器列表
控制结构{%...%},可用来改变模板的渲染流程 if, for, macro, import, include
需要在多处重复使用的模板代码片段可以写入单独的文件,再包含 {%include 'common.html' %} 在所有模板中
另一种重复使用代码的强大方式是模板继承,block标签定义的元素可在衍生模板中修改
[html] view plain copy
extends指令声明这个模板衍生自base.html。在extends指令之后,基模板中的3个块被重新定义,模板引擎会将其插入适当的位置。注意新定义的head块,在基模板中其内容不是空的,所以使用super()获取原来的内容(向已经有内容的块中添加新内容)。
[html] view plain copy
使用Flask-Bootstrap
Bootstrap是客户端框架,因此不会直接涉及服务器。服务器需要做的只是提供引用了Bootstrap层 叠样式表(CSS)和JavaScript文 件的HTML响 应,并在HTML、CSS和JavaScript代码中实例化所需组件。这些操作最理想的执行场所就是模板。
Flask-Bootstrap基模板中定义的块:doc, head, title, styles, body, navbar, content, scripts
Bootstrap官方文档
CDN本地加速:
修改 Base.html,引用本地的css 文件,里面元素跟Bootstrap 重名的,则会覆盖官方里相同元素
[html] view plain copy
2016-10-20: 以上本地加速证明是有误的!会重复下载本地和官方Bootstrap 的 css/js
解决:
/app/__init__.py
from flask_bootstrap import Bootstrap, WebCDN, ConditionalCDN, BOOTSTRAP_VERSION, JQUERY_VERSION, HTML5SHIV_VERSION, RESPONDJS_VERSION
def create_app(config_name):
[python] view plain copy
另外:本地加速 moment.js
这个文件也在国外服务器,访问很慢,而且 size=160KB
/app/templates/base.html
{% block scripts %}
{{ super() }}
{{ moment.include_moment(local_js="/static/moment-with-locales.min.js") }}
{{ moment.lang('zh-CN') }}
{% endblock %}
需要单独下载 https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.3/moment-with-locales.min.js 到本地目录 /app/static/
自定义错误页面
[python] view plain copy
url_for() 链接辅助函数
使用url_for()生成动态地址时,将动态部分作为关键字参数传入。例如,
url_for('user', name='john', _external=True)的返回结果是http://localhost:5000/user/john
使用Flask-Moment本地化日期和时间。查阅文档
[html] view plain copy
app.config字典可用来存储框架、扩展和程序本身的配置变量。使用标准的字典句法就能把配置值添加到app.config对象中。这个对象还提供了一些方法,可以从文件或环境中导入配置值。
Form基类由Flask-WTF扩展定义,所以从flask.ext.wtf中导入。字段和验证函数 可以直接从WTForms包中导入。
[python] view plain copy
WTForms支持的HTML标准字段:StringField,TextAreaField,PasswordField。。。
WTForms内建的验证函数:Email,DataRequired...
Placeholder提示:
[python] view plain copy
重定向和用户会话
刷新页面后会再次提交表单。大多数情况下,这并不是理想的处理方式。
很多用户都不理解浏览器发出的这个警告。 基于这个原因,最好别让 Web 程序把 POST 请求作为浏览器发送的最后一个请求。
这个技巧称为Post/重定向/Get模式。
[python] view plain copy
使用get()获取字典中键对应的值以避免未找到键的异常情况,因为对于不存在的键,get()会返回默认值None。
Flash消息
仅调用flash()函数并不能把消息显示出来,程序使用的模板要渲染这些消息。最好在base.html 中渲染Flash消息,因为这样所有页面都能使用这些消息。Flask把get_flashed_messages()函数开放给模板,用来获取并渲染消息
2016-6-9
使用SQL还是NoSQL
SQL 数据库擅于用高效且紧凑的形式存储结构化数据。这种数据库需要花费大量精力保证数据的一致性。NoSQL 数据库放宽了对这种一致性的要求,从而获得性能上的优势。
MySQL Q&A:
安装MySQL in Windows 报错:需要预先把Windows Defender 打开,或者configure mysql server时,不要勾选“Windows Firewall”
可能要先安装:Microsoft Visual C++ Compiler for Python 2.7
本地安装MySQLdb: pip install mysql-python
Window7 64位下安装可能还会报 cl.exe错
workaround: 先conda install mysql-python,再手动复制以下目录及文件到 venv\Lib\Site-packages下:
Anaconda2\Lib\site-packages\MySQLdb
Anaconda2\Lib\site-packages\MySQL_python-1.2.5.dist-info
Anaconda2\Lib\site-packages\_mysql*
MySQL创建connection之后,还需要创建“schema” --> 对应SQLAlchemy里的“database”
MySQLdb 中文乱码的处理:
conn = MySQLdb.connect(host='localhost', user='root', passwd='XXX', db='app_englishgo', charset = 'utf8')
显示:title.encode('gbk')
接收输入:unicode(request.form['title'])
SQLAlchemy 和MongoEngine:数据库抽象层代码包(ORM、ODM),你可以使用这些抽象包直接处理高等级的 Python 对象,而不用处理如表、文档或查询语言此类的数据库实体。
使用Flask-SQLAlchemy管理数据库
MySQL mysql://username:password@hostname:port/database
SQLite(Windows) sqlite:///c:/absolute/path/to/database
Relationship 关系型数据库
[python] view plain copy
SQLAlchemy 完整的命令、过滤器、查询执行 列表参见 SQLAlchemy 文档
SQLAlchemy engine设置编码,防止中文乱码:
[python] view plain copy
[python] view plain copy
集成python shell
每次启动 shell 会话都要导入数据库实例和模型。为避免重复导入,我们可以做些配置,让 Flask-Script 的 shell 命令自动导入特定的对象。为 shell 命令注册一个 make_context 回调函数
新数据库迁移 flask-migrate
由于模型中经常会新加一行或几行column (比如用来保存账户的确认状态),此时要修改 models.py,并执行一次新数据库迁移
MySQL Workbench 自动产生EER,可以清楚地看到各个表格之间关系:一对多 Foreign_Key、Index等
1) config.py:
[python] view plain copy
2) python manage.py deploy
3) mysql Workbench: Database -> Reverse Engineer -> 选择 connection -> database -> 一路 Next
使用Flask-Mail提供电子邮件支持
[python] view plain copy
千万不要把账户密令直接写入脚本,特别是当你计划开源自己的作品时。让脚本从本机环境中导入敏感信息Windows 用户可按照下面的方式设定环境变量:
[plain] view plain copy
所有的在cmd命令行下对环境变量的修改只对当前窗口有效,不是永久性的修改。也就是说当关闭此cmd命令行窗口后,将不再起作用。永久性修改环境变量的方法有两种:一种是直接修改注册表(overkill python script),另一种是通过我的电脑-〉属性-〉高级,来设置系统的环境变量
异步发送电子邮件
为了避免处理请求过程中不必要的延迟,我们可以把发送电子邮件的函数移到后台线程(Threading)中
很多 Flask 扩展都假设已经存在激活的程序上下文和请求上下文。Flask-Mail 中的 send() 函数使用 current_app ,因此必须激活程序上下文。不过,在不同线程中执行 mail.send() 函数时,程序上下文要使用 app.app_context() 人工创建。
项目结构
[plain] view plain copy
requirements.txt 文件,用于记录所有依赖包及其精确的版本号。以便要在另一台电脑上重新生成虚拟环境
创建:(venv) $ pip freeze > requirements.txt
恢复:(venv) $ pip install -r requirements.txt
重组后的程序和单脚本版本使用不同的数据库,可使用如下命令创建数据表或者升级到最新修订版本:(venv) $ python manage.py db upgrade
Flask的认证扩展
Flask-Login:管理已登录用户的用户会话。
Werkzeug:计算密码散列值并进行核对。
itsdangerous:生成并核对加密安全令牌。
创建认证蓝本
对于不同的程序功能,我们要使用不同的蓝本(main, auth),这是保持代码整齐有序的好方法
因为 Flask 认为模板的路径是相对于程序模板文件夹而言的。为避免与 main 蓝本和后续添加的蓝本发生模板命名冲突,可以把蓝本使用的模板保存在单独的文件夹中
使用Flask-Login认证用户
LoginManager 对象的 session_protection 属性可以设为 None 、 'basic' 或 'strong' ,以提供不同的安全等级防止用户会话遭篡改。设为 'strong' 时,Flask-Login 会记录客户端 IP地址和浏览器的用户代理信息,如果发现异动就登出用户。
为了保护路由只让认证用户访问,Flask-Login 提供了一个 login_required 修饰器
current_user 由 Flask-Login 定义,且在视图函数和模板中自动可用
模板中加入用户登录后的信息和提示效果 base.html:
[html] view plain copy
按照第 4 章介绍的“Post/ 重定向 /Get 模式”,Login的 POST 请求最后也做了重定向,不过目标 URL 有两种可能。用户访问未授权的 URL 时会显示登录表单,Flask-Login 会把原地址保存在查询字符串的next参数中,这个参数可从 request.args 字典中读取。如果查询字符串中没有 next 参数,则重定向到首页
app/auth/views.py
[python] view plain copy
用户注册表单 app/auth/forms.py
这个表单使用 WTForms 提供的 Regexp 验证函数,确保 username 字段只包含字母、数字、下划线和点号。
密码要输入两次。此时要验证两个密码字段中的值是否一致,这种验证可使用WTForms 提供的另一验证函数实现,即 EqualTo
如果表单类中定义了以validate_ 开头且后面跟着字段名的方法,这个方法就和常规的验证函数一起调用
发送确认邮件
使用itsdangerous生成确认令牌
[python] view plain copy
对蓝本来说, before_request 钩子只能应用到属于蓝本的请求上。若想在蓝本中使用针对程序全局请求的钩子,必须使用 before_app_request 修饰器
2016-6-10
角色在数据库中的表示
赋予角色
角色验证
2016-6-10
用户资料页面
资料编辑器
用户头像
国内 gravatar.com被墙,改用其它方法:静态jpg头像
目录:c:\git\flasky\app\static\avatar\001.jpg ~ XXX.jpg
base.html:
[html] view plain copy
models.py:
[python] view plain copy
user.html:
[html] view plain copy
_posts.html:
[html] view plain copy
_commments.html:
[html] view plain copy
效果:
扩展TODO:加入性别、用户自选头像。。。
2016-6-12
实现功能,即允许用户阅读、撰写博客文章。本章新技术:重用模板、分页显示长列表以及处理富文本。
生成虚拟信息用于测试,其中功能相对完善的是ForgeryPy
[python] view plain copy
添加分页导航
paginate() 方法的返回值是一个 Pagination 类对象,这个类在 Flask-SQLAlchemy 中定义。这个对象包含很多属性, 用于在模板中生成分页链接
使用Markdown和Flask-PageDown支持富文本文章
• PageDown: 使用JavaScript实现的客户端Markdown到HTML的转换程序。
• Flask-PageDown: 为Flask包装的PageDown,把PageDown集成到Flask-WTF表单中。
• Markdown: 使用Python实现的服务器端Markdown到HTML的转换程序。
• Bleach: 使用Python实现的HTML清理器。
博客文章的固定链接
博客文章编辑器
2016-6-12
再论数据库关系
一对多关系:是最常用的关系类型,它把一个记录和一组相关的记录联系在一起。实现这种关系时,要在“多”这一侧加入一个外键,指向“一”这一侧联接的记录。
多对多关系: 这种问题的解决方法是添加第三张表, 这个表称为关联表。多对多关系可以分解成原表和关联表之间的两个一对多关系
若想显示所关注用户发布的所有文章,第一步显然先要获取这些用户,然后获取各用户的文章,再按一定顺序排列,写入单独列表。可是这种方式的伸缩性不好,随着数据库不断变大,生成这个列表的工作量也不断增长,而且分页等操作也无法高效率完成。获取博客文章的高效方式是只用一次查询。
完成这个操作的数据库操作称为联结。联结操作用到两个或更多的数据表, 在其中查找满足指定条件的记录组合, 再把记录组合插入一个临时表中,这个临时表就是联结查询的结果。
创建函数更新数据库这一技术经常用来更新已部署的程序,因为运行脚本更新比手动更新数据库更少出错。
评论属于某篇博客文章,因此定义了一个从posts表到comments表的一对多关系。使用这个关系可以获取某篇特定博客文章的评论列表。
comments 表还和 users 表之间有一对多关系。通过这个关系可以获取用户发表的所有评论,还能间接知道用户发表了多少篇评论
管理评论,我们要在导航条中添加一个链接,具有权限的用户才能看到。
2016-6-12
资源就是一切
资源是REST架构方式的核心概念。在REST架构中, 资源是程序中你要着重关注的事物。例如,在博客程序中,用户、博客文章和评论都是资源。
创建新的Shell命令 deploy:
[python] view plain copy
Flask自带的开发Web服务器表现很差,因为它不是为生产环境设计的服务器。有两个可以在生产环境中使用、性能良好且支持Flask程序的服务器,分别是 Gunicorn 和 uWSGI。
manage:app参数冒号左边的部分表示定义程序的包或者模块,冒号右边的部分表示包中程序实例的名字。注意,Gunicor默认使用端口8000,而Flask默认使用5000。
添加ProxyFix等WSGI中间件的方法是包装WSGI程序。收到请求时,中间件有机会审查环境,在处理请求之前做些修改。不仅Heroku需要使用ProxyFix中间件,任何使用反向代理的部署环境都需要。
架设服务器
在能够托管程序之前,服务器必须完成多项管理任务。
Flask-Cache插件为你提供一组装饰器来实现多种方式的缓存
开发自定义视图装饰器来帮助我们组织自己的代码
自定义的URL转换器将会让你很嗨地玩转URL:https://spacewander.github.io/explore-flask-zh/6-advanced_patterns_for_views_and_routing.html
Write a Tumblelog Application with Flask and MongoEngine
这是MongoDB官方文档中的一个教程,也是学习Flask开发的一个很好案例,尤其适合Flask+mongodb开发的应用场景
The Hitchhiker’s Guide to Python!
这个资料虽然不直接与Flask有关,但对初学者,绝对有学习的价值
GitHub - humiaozuzu/awesome-flask: A curated list of awesome Flask resources and plugins
The Flask Mega-Tutorial, Part I: Hello, World! - miguelgrinberg.com
大多数内容是本书上写的更加 advanced,但以下话题只在“Mega Tutorial”里提到:
一些值得研究的包。
Flask官方扩展网站
PEP 8: 每级缩进使用4个空格。不要使用tab
PEP 257: docstrings""" docstrings """
用了相对形式的import 点标记法:第一个.来表示当前目录,之后的每一个.表示下一个父目录。
from .modelsimport User
https://spacewander.github.io/explore-flask-zh/7-blueprints.html
什么是蓝图?
一个蓝图定义了可用于单个应用的视图,模板,静态文件等等的集合。举个例子,想象一下我们有一个用于管理面板的蓝图。这个蓝图将定义像/admin/login和/admin/dashboard这样的路由的视图。它可能还包括所需的模板和静态文件。你可以把这个蓝图当做你的应用的管理面板,管它是宇航员的交友网站,还是火箭推销员的CRM系统。
蓝图的杀手锏是将你的应用组织成不同的组件。假如我们有一个微博客,我们可能需要有一个蓝图用于网站页面,比如index.html和about.html。然后我们还需要一个用于在登录面板中展示最新消息的蓝图,以及另外一个用于管理员面板的蓝图。站点中每一个独立的区域也可以在代码上隔绝开来。最终你将能够把你的应用依据许多能完成单一任务的小应用组织起来。
Flask.register_blueprint()
注册它。
pip install flask-sqlalchemy
pip install flask-login
...
from flask.ext.bootstrap import Bootstrap
bootstrap = Bootstrap(app)
然后 /template/目录下创建自己的 html,{% extends "bootstrap/base.html" %}
模板:\Lib\site-packages\flask_bootstrap\templates\bootstrap\
Bootstrap 导航栏 自定义配色:
{% block styles %}
{{super()}}
{% endblock %}
其中 style.css 可以包含自定义的 .navbar-kevin {。。。}
配色方案 http://work.smarchal.com/twbscolor/
修改文件:/app/__init__.py
[python] view plain copy
文章标签: pythonwebflaskweb框架