30分钟搭建Python的Flask框架并在上面编写第一个应用


Posted in Python onMarch 30, 2015

Flask 是一种很赞的Python web框架。它极小,简单,最棒的是它很容易学。
30分钟搭建Python的Flask框架并在上面编写第一个应用今天我来带你搭建你的第一个Flask web应用!和官方教程 一样,你将搭建你自己的微博客系统:Flaskr。和官方Flask教程不同的是——我们通过使用Stormpath来创建并管理用户账户和数据,你的工作效率会更高。开发进程会显著地加快!

我们这就开始吧。

注意:这篇教程面向Flask开发新人,帮助他们理解如何使用Flask和Stormpath建立一个简单的网站。本文是Flask官方教程的改版。
目标

Flaskr 应用的目标很简单:

  •     允许用户以事先生成的账户(使用Stormpath保存)登录、登出本微博客系统。
  •     允许登入用户在页面添加包含了纯文本和一些HTML body文本的条目。用户被认为是可信任的,HTML内容不会被审查。
  •     以时间顺序(新的在最上)在网站主页显示所有博客条目。

最终的网站应该看起来像这样:
30分钟搭建Python的Flask框架并在上面编写第一个应用准备

开始之前,我们需要先安装一些Python包才能干活!我们通过?Python包管理器pip来完成这件事。
 pip install flask flask-stormpath

上述命令会安装两个包:Flask, 和Flask-Stormpath,这两个包在整篇教程都会用到。

接着,你需要创建一个Stormpath账户。你可以在Stormpath网站注册:https://api.stormpath.com/register

当你创建了一个Stormpath账户并登入后,你还需要创建一个API 密钥。你可以在操作页面上点击创建API密钥按钮来完成:https://api.stormpath.com/ui/dashboard

创建了API密钥后,你会被提示要去下载一个名为apiKey.properties的文件,稍后我们将用到它。

注意:不要把apiKey.properties文件检入你的版本控制系统(如果你在用的话)!这个文件存储着你的Stormpath证书,应该被妥善保管。

接着,你会想要创建新的Stormpath应用,请访问应用网页:https://api.stormpath.com/v#!applications?,点击注册应用。创建一个名为flaskr的新应用,选项按默认的来。

最后,访问账户页面:https://api.stormpath.com/ui/accounts/create? ,在flaskr Directory创建新用户账户。所有在这儿创建的账户都可以用来登入你将搭建的微博客。
目录结构

你要做的第一件事就是创建一个存放你应用代码的目录结构。你需要创建若干目录,然后把你的apiKey.properites?放到新建的项目目录:
 

$ mkdir -p flaskr/{static,templates}; cp ~/path/to/apiKey.properties flaskr/
$ tree flaskr
flaskr
├── apiKey.properties
├── static
└── templates
 
2 directories, 1 file

flaskr目录将是你应用的根目录。static目录用于存放你的静态文件(css,javascript, 和图像文件).templates目录用于存放你的Jinja模板(用于渲染HTML)。
安装应用

现在你的目录结构搭好了,我们开始配置应用了!

首先,在你flaskr目录下创建名为flaskr.py的新文件。你的应用代码放在这个文件里。

一切将从这里开始:

from datetime import datetime
 
from flask import (
 Flask,
 abort,
 flash,
 redirect,
 render_template,
 request,
 url_for,
)
from flask.ext.stormpath import (
 StormpathError,
 StormpathManager,
 User,
 login_required,
 login_user,
 logout_user,
 user,
)
 
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'some_really_long_random_string_here'
app.config['STORMPATH_API_KEY_FILE'] = 'apiKey.properties'
app.config['STORMPATH_APPLICATION'] = 'flaskr'
 
stormpath_manager = StormpathManager(app)
 
if __name__ == '__main__':
 app.run()

需要关注的:

  •     在flaskr.py文件的开头你导入了若干库——下面整篇教程都会用到它们
  •     你创建了一个app对象——这是每个Flask 项目的核心
  •     你在app.config里添加了若干配置变量。app.config是一个Python字典变量,你可以用它存放你想存放的任何定制配置。这里我们设置了若干后面会用到的重要的变量:
  •         DEBUG 变量可以设置为True或者False。它用于控制Flask的内置错误报告行为(开发模式下它让Flask可以显示详细的错误信息)
  •         SECRET_KEY 变量在内部使用,用来保证客户端的会话安全。当部署一个真正的Flask应用时,要确保这是一个较长的随机生成的字符串。
  •         STORMPATH_API_KEY_FILE? 变量应该指向你的apiKey.properties 文件位置。更多信息参见:http://flask-stormpath.readthedocs.org/en/latest/setup.html
  •         STORMPATH_APPLICATION 变量应该是你之前创建的Stormpath 应用名。
  •     你创建了一个stormpath_manager 对象,它用于控制Stormpath 库,后面将帮你轻松与用户以及用户数据进行交互。
  •     You're calling?app.run()?at the bottom. This tells Flask to run your site in development mode for testing.
  •     在最后你调用了app.run()?。它告诉Flask以开发模式运行你的网站以便于测试。

运行下述命令之后,你就可以看到你的Flask应用开始在端口5000运行:

$ python flaskr.py
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader

不过当你访问http://127.0.0.1:5000, 你会看到一个404 not found 信息。这是因为你还没有定义任何视图或者URL路由 。
视图

现在安装的部分你已经做完了,我们来定义视图。下面的代码应该放在flaskr.py 文件中,在这个上面:

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

代码如下:

@app.route('/')
def show_posts():
 posts = []
 for account in stormpath_manager.application.accounts:
  if account.custom_data.get('posts'):
   posts.extend(account.custom_data['posts'])
 
 posts = sorted(posts, key=lambda k: k['date'], reverse=True)
 return render_template('show_posts.html', posts=posts)
 
@app.route('/add', methods=['POST'])
@login_required
def add_post():
 if not user.custom_data.get('posts'):
  user.custom_data['posts'] = []
 
 user.custom_data['posts'].append({
  'date': datetime.utcnow().isoformat(),
  'title': request.form['title'],
  'text': request.form['text'],
 })
 user.save()
 
 flash('New post successfully added.')
 return redirect(url_for('show_posts'))
 
@app.route('/login', methods=['GET', 'POST'])
def login():
 error = None
 
 if request.method == 'POST':
  try:
   _user = User.from_login(
    request.form['email'],
    request.form['password'],
   )
   login_user(_user, remember=True)
   flash('You were logged in.')
 
   return redirect(url_for('show_posts'))
  except StormpathError, err:
   error = err.message
 
 return render_template('login.html', error=error)
 
@app.route('/logout')
def logout():
 logout_user()
 flash('You were logged out.')
 
 return redirect(url_for('show_posts'))

我们来讨论一下上面的代码。

你可能注意到首先定义的函数是show_posts。这个函数用于在网站前端页面显示发布的博文。如你可能已经猜到的,装饰器@app.route(‘/')告诉Flask如何运行这个函数。

每次用户请求 URL “/”,Flask就会运行show_posts,把输出返回给用户。

show_posts 就只是:

  •     迭代所有的用户账户,查找博文。每篇博文就是一个简单的如下格式的Python字典: 
{
 'date': '2014-04-01T22:50:49.762475',
 'text': 'Blog content.',
 'title': 'Post title'
}
  •     每找到一篇博文就添加到posts数组。
  •     按日期对posts数组排序,因此新发布的在前面。
  •     以posts数组作为输入,渲染出一个叫做show_posts.html的HTML模板.
  • add_posts 视图用于登入用户向网站发布新博文。这个视图带来下面几样东西:
  •     装饰器@app.route(‘/add', methods=[‘POST'])告诉Flask该URL只接受POST请求。Flask默认只接受GET请求。
  •     @login_required 装饰器确保能访问该视图前用户已经登入。如果用户没有登入而尝试对该视图POST,会得到HTTP 401 未授权应答。
  •     任何装饰了?@login_required的视图都可以访问user变量。这是一个存放了用户账户细节的对象。

它的工作机制很简单:

  •     检查用户账户下是否有保存的博文。这一步是通过检查user.custom_data.get(‘posts') 不是False来实现的。user.custom_data是一个Python字典,你可以在其中保存任何想保存的用户数据。
  •     从POST 请求中抓取标题和正文,在用户的posts数组中创建一个新的post对象。
  •     保存新博文到用户账户的Stormpath中。
  •     发出一个后面会向用户展示的消息。
  •     最后,把用户重定向到show_posts?视图,让新添加的博文可以展现出来。
  •     login 和logout视图特别地简单。

login视图就是简单地从用户POST请求中提取电子邮件地址和密码,然后从Stormpath抓取user对象,尝试登录,并创建一个本地会话。

logout视图就是销毁用户会话。
模板

下一样要加入的东西就是模板代码。Flask使用Jinja模板语言,它让编写HTML模板变得非常简单。

让我们定义一个布局模板templates/layout.html作为开始。后面我们写的其他模板都将从这个基础模板而来。这个策略很有用,因为它允许你在一个地方定义会被多次引用的模板代码。

把下面的代码添加到你的layout.html模板文件:
 

<!doctype html>
<title>Flaskr</title>
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
<div>
 <h1>Flaskr</h1>
 <div>
 {% if user.email %}
 <a href="{{ url_for('logout') }}">log out</a>
 {% else %}
 <a href="{{ url_for('login') }}">log in</a>
 {% endif %}
 </div>
 {% for message in get_flashed_messages() %}
 <div>{{ message }}</div>
 {% endfor %}
 {% block body %}{% endblock %}
</div>

接着是templates/show_posts.html 模板文件:
 

{% extends "layout.html" %}
{% block body %}
 {% if user.email %}
 <form action="{{ url_for('add_post') }}" method=post>
  <dl>
  <dt>Title:
  <dd><input type=text size=30 name=title>
  <dt>Text:
  <dd><textarea name=text rows=5 cols=40></textarea>
  <dd><input type=submit value=Share>
  </dl>
 </form>
 {% endif %}
 <ul>
 {% for post in posts %}
 <li><h2>{{ post['title'] }}</h2>{{ post['text']|safe }}
 {% else %}
 <li><em>Unbelievable. No posts here so far!</em>
 {% endfor %}
 </ul>
{% endblock %}

最后,是templates/login.html 模板文件:
 

{% extends "layout.html" %}
{% block body %}
 <h2>Login</h2>
 {% if error %}<p><strong>Error:</strong> {{ error }}{% endif %}
 <form action="{{ url_for('login') }}" method=post>
 <dl>
  <dt>Email:
  <dd><input type=text name=email>
  <dt>Password:
  <dd><input type=password name=password>
  <dd><input type=submit value=Login>
 </dl>
 </form>
{% endblock %}

首先要注意的是?layout.html模板定义了一个body块,在任何子模板中它都可以被同名的块替代。

layout.html模板显示了一个login或者logout模板,还显示所有的闪回信息。
 

{% if user.email %}

因为你用的是Flask-Stormpath,所有模板都可以访问一个神奇的user 变量。当一个用户登入后,该用户的所有细节都是可见的(因此这个检查能生效)。

show_posts.html?模板迭代posts数组,它是被show_posts视图调用render_template时传入的。Jinja允许你对任何可以迭代的东西使用for循环。

还有很重要的一点,为了输出变量内容,你需要在变量外面加上花括号.
 

{{ variable }}
 
{{ post['text']|safe }}

既然我们决定了允许用户在他们的博文中输入任性的HTML代码,我们就得使用模板的safe过滤器来输出博文中的body块。

Jinja默认会自动忽略任何特殊字符,所以我们得使用safe过滤器来显示用户输入的HTML和Javascript。
添加样式

最后一件要做的就是创建一个带有如下内容的static/style.css 文件:
 

body   { font-family: sans-serif; background: #eee; }
a, h1, h2  { color: #377ba8; }
h1, h2   { font-family: 'Georgia', serif; margin: 0; }
h1    { border-bottom: 2px solid #eee; }
h2    { font-size: 1.2em; }
 
.page   { margin: 2em auto; width: 35em; border: 5px solid #ccc;
     padding: 0.8em; background: white; }
.entries  { list-style: none; margin: 0; padding: 0; }
.entries li  { margin: 0.8em 1.2em; }
.entries li h2 { margin-left: -1em; }
.add-entry  { font-size: 0.9em; border-bottom: 1px solid #ccc; }
.add-entry dl { font-weight: bold; }
.metanav  { text-align: right; font-size: 0.8em; padding: 0.3em;
     margin-bottom: 1em; background: #fafafa; }
.flash   { background: #cee5F5; padding: 0.5em;
     border: 1px solid #aacbe2; }
.error   { background: #f0d6d6; padding: 0.5em; }

这个文件会被layout.html 模板加载,提供得体的显示风格。
测试它

现在我们完成了应用的编码,让我们看看最终的产品吧!

为了运行你炫酷的新网站,你得首先通过如下命令来重新启动Flask web 服务器:
 

$ python flaskr.py
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader

然后在你的浏览器访问http://127.0.0.1:5000吧。你现在应该能看到正在运行的flaskr 网站,并能使用Stormpath 账户登入,发博文等等。

Python 相关文章推荐
python执行shell获取硬件参数写入mysql的方法
Dec 29 Python
Python调用C语言开发的共享库方法实例
Mar 18 Python
Python中动态创建类实例的方法
Mar 24 Python
Python iter()函数用法实例分析
Mar 17 Python
Python实现的各种常见分布算法示例
Dec 13 Python
python中时间模块的基本使用教程
May 14 Python
pandas 使用均值填充缺失值列的小技巧分享
Jul 04 Python
python FTP批量下载/删除/上传实例
Dec 22 Python
Python3实现mysql连接和数据框的形成(实例代码)
Jan 17 Python
解决pyPdf和pyPdf2在合并pdf时出现异常的问题
Apr 03 Python
python操作链表的示例代码
Sep 27 Python
python数字类型和占位符详情
Mar 13 Python
编写同时兼容Python2.x与Python3.x版本的代码的几个示例
Mar 30 #Python
以Python的Pyspider为例剖析搜索引擎的网络爬虫实现方法
Mar 30 #Python
在树莓派2或树莓派B+上安装Python和OpenCV的教程
Mar 30 #Python
Python中利用函数装饰器实现备忘功能
Mar 30 #Python
利用Python绘制MySQL数据图实现数据可视化
Mar 30 #Python
Python面向对象编程中的类和对象学习教程
Mar 30 #Python
详细介绍Python函数中的默认参数
Mar 30 #Python
You might like
php MYSQL 数据备份类
2009/06/19 PHP
PHP的变量类型和作用域详解
2014/03/12 PHP
PHP类与对象后期静态绑定操作实例详解
2018/12/20 PHP
xheditor与validate插件冲突的解决方案
2010/04/15 Javascript
FireFox下XML对象转化成字符串的解决方法
2011/12/09 Javascript
Javascript中valueOf与toString区别浅析
2013/03/19 Javascript
定时器(setTimeout/setInterval)调用带参函数失效解决方法
2013/03/26 Javascript
jquery库或JS文件在eclipse下报错问题解决方法
2014/04/17 Javascript
JavaScript函数模式详解
2014/11/07 Javascript
2014 年最热门的21款JavaScript框架推荐
2014/12/25 Javascript
jquery获取当前日期的方法
2015/01/14 Javascript
nodejs 整合kindEditor实现图片上传
2015/02/03 NodeJs
JavaScript基于setTimeout实现计数的方法
2015/05/08 Javascript
JS实现支持多选的遍历下拉列表代码
2015/08/20 Javascript
JS随机洗牌算法之数组随机排序
2016/03/23 Javascript
微信小程序 两种为对象属性赋值的方式详解
2017/02/23 Javascript
原生JS实现不断变化的标签
2017/05/22 Javascript
完美解决mui框架off-canvas侧滑超出部分隐藏无法滚动的问题
2018/01/25 Javascript
vue计算属性和监听器实例解析
2018/05/10 Javascript
taro开发微信小程序的实践
2019/05/21 Javascript
使用axios请求时,发送formData请求的示例
2019/10/29 Javascript
在Vue 中获取下拉框的文本及选项值操作
2020/08/13 Javascript
python求crc32值的方法
2014/10/05 Python
python 实现对文件夹内的文件排序编号
2018/04/12 Python
基于Python列表解析(列表推导式)
2018/06/23 Python
Django-Rest-Framework 权限管理源码浅析(小结)
2018/11/12 Python
使用python实现语音文件的特征提取方法
2019/01/09 Python
使用Python实现批量ping操作方法
2020/05/06 Python
pandas按条件筛选数据的实现
2021/02/20 Python
深入CSS3 动画效果的总结详解
2013/05/09 HTML / CSS
Laura官网:加拿大女性的顶级时尚目的地
2019/09/20 全球购物
丧事主持词大全
2014/04/02 职场文书
群众路线个人整改方案
2014/10/25 职场文书
入党自荐书范文
2015/03/05 职场文书
基于Redis延迟队列的实现代码
2021/05/13 Redis
python数字图像处理之对比度与亮度调整示例
2022/06/28 Python