配置MongoDB
1.在工程中配置MongoDB,首先在config.py中进行添加:
1 |
MONGODB_SETTINGS = {'DB': 'todo_db'} |
2.在__init__.py中导入MongoEngine,并且实例化:
1 2 3 4 5 6 7 8 9 |
from flask import Flask from flask.ext.mongoengine import MongoEngine app = Flask(__name__) app.config.from_object("config") db = MongoEngine(app) from app import views, models |
3.然后创建数据模型,用于映射MongoDB中的Document对象,在model.py中:
1 2 3 4 5 6 7 |
from app import db import datetime class Todo(db.Document): content = db.StringField(required=True, max_length=20) time = db.DateTimeField(default=datetime.datetime.now()) status = db.IntField(default=0) |
后台
在view.py中,要从后台数据库获取所有的todo
1 2 3 4 |
@app.route('/') def index(): todos = Todo.objects.all() return render_template("index.html", todos=todos) |
之前我们都是用manage.py脚本保存的Todo,那如何在前端浏览器上添加呢?
- 使用表单接受输入,并传给Flask后台。
- Flask获取到前端来的数据后,将数据保存到MongoDB中。
- 前端
在index.html模板中,加入一个表单,可以输入todo的内容。
- 后台
然后在view.py中
1 2 3 4 5 6 7 |
@app.route('/add', methods=['POST', ]) def add(): content = request.form.get("content") todo = Todo(content=content) todo.save() todos = Todo.objects.all() return render_template("index.html", todos=todos) |
单元测试就是让我们代码的健壮性大大提高
注意点
用了相对形式的import后,你可以使用点标记法:第一个.来表示当前目录,之后的每一个.表示下一个父目录。
- Python导入模块的几种姿势
- Python 中 import 的机制与实现
- Python包的相对导入时出现“ ‘Parent module ‘ not loaded, cannot perform relative import”的解决方法
文件结构
当你开始在一个变得更加复杂的项目上工作时,单一模块就会造成严重的问题。
你需要为模型(model)和表单(form)定义多个类,而它们会跟你的路由和配置代码又吵又闹。所有的一切让你焦头烂额。
为了解决这个问题,我们得把应用中不同的组件分开到单独的、高内聚的一组模块 – 也即是包 – 之中
__init__.py
# 空的,只是用来告诉Python它是一个包。
有关模型的类定义全待在models.py,而路由定义在views.py,有关表单的类定义全待在forms.py(我们等会会用整整一章的篇幅谈谈表单)
配置
为了加载这些配置变量,我通常使用app.config.from_object()。如果是单一模块应用中,是在app.py;或者在yourapp/__init__.py,如果是基于包的应用。
无论在哪种情况下,代码看上去像这样:
1 2 3 4 5 |
from flask import Flask app = Flask(__name__) app.config.from_object('config') # 现在通过app.config["VAR_NAME"],我们可以访问到对应的变量 |
instance文件夹
有时你需要定义一些不能为人所知的配置变量。为此,你会想要把它们从config.py中的其他变量分离出来,并保持在版本控制之外。
你可能要隐藏类似数据库密码和API密钥的秘密,或定义特定于当前机器的参数。
为了让这更加轻松,Flask提供了一个叫instance文件夹的特性。
instance文件夹是根目录的一个子文件夹,包括了一个特定于当前应用实例的配置文件。
关于视图和路由的进阶技巧
认证
Flask-Login使得用户认证系统的实现不再困难。
除了处理用户认证的细节之外,Flask-Login允许我们使用@login_required这个装饰器来验证用户对某些资源的访问权限。
1 2 3 4 5 6 7 8 9 10 11 |
from flask import render_template from flask_login import login_required, current_user @app.route('/') def index(): return render_template("index.html") @app.route('/dashboard') @login_required def account(): return render_template("account.html") |
@app.route必须是最外面的视图装饰器。
只有已经验证的用户能够接触到/dashboard路由。你可以配置Flask-Login来重定向未验证用户到登录页面,返回HTTP 401状态码或别的你乐意的事。
缓存
意淫一下,假如你的应用突然有一天在微博/朋友圈或网上别的地方火了。
于是秒秒钟会有成千上万的请求涌向你的应用。你的主页在每个请求中都要从数据库跑上一大趟,结果海量的请求导致网站慢得像教务系统一样。
你能做什么来加速这一过程,以免用户以为你的应用挂掉了?
答案不止一个,不过就本章主旨而言,标准答案是实现缓存。
特别的,我们将要用到Flask-Cache拓展。这个拓展给我们提供一个可以用来缓存某个响应一段时间的装饰器。
蓝图
什么是蓝图?
一个蓝图定义了可用于单个应用的视图,模板,静态文件等等的集合。
蓝图的杀手锏是将你的应用组织成不同的组件。假如我们有一个微博客,我们可能需要有一个蓝图用于网站页面,比如index.html和about.html。然后我们还需要一个用于在登录面板中展示最新消息的蓝图,以及另外一个用于管理员面板的蓝图。站点中每一个独立的区域也可以在代码上隔绝开来。最终你将能够把你的应用依据许多能完成单一任务的小应用组织起来
把它们放到哪里?
功能式架构
在功能式架构中,按照每部分代码的功能来组织你的应用。所有模板放到同一个文件夹中,静态文件放在另一个文件夹中,而视图放在第三个文件夹中
除了yourapp/views/__init__.py,在yourapp/views/文件夹中的每一个.py文件都是一个蓝图。在yourapp/__init__.py中,我们将加载这些蓝图并在我们的Flask()对象中注册它们。等会我们将在本章了解到这是怎么实现的。
分区式架构
在分区式架构中,按照每一部分所属的蓝图来组织你的应用。管理面板的所有的模板,视图和静态文件放在一个文件夹中,用户控制面板的则放在另一个文件夹中。
在像上面列举的分区式结构,每一个yourapp/之下的文件夹都是一个独立的蓝图。所有的蓝图通过顶级的__init__.py注册到Flask()中。
下面是一个非常精简的可能的Facebook结构,假定它用的是Flask。
现在我们已经定义好了蓝图。是时候向Flask app注册它了。
- 下面我们在实例化的时候设置URL前缀:
facebook/views/profile.py
1 2 3 |
from flask import Blueprint, render_template profile = Blueprint('profile', __name__, url_prefix='/<user_url_slug>') |
- 下面我们在注册的时候设置URL前缀:
facebook/__init__.py
1 2 3 4 5 |
from flask import Flask from .views.profile import profile app = Flask(__name__) app.register_blueprint(profile, url_prefix='/<user_url_slug>') |
尽管这两种方式在技术上没有区别,最好还是在注册的同时定义前缀。这使得前缀的定义可以集中到顶级目录中。因此,我推荐使用url_prefix。
存储
flask-sqlalchemy使用MySQL的方式是:mysql://username:password@server/db
We’re going to define some models then configure some SQLAlchemy. The models are going to go in myapp/models.py, but first we are going to define our database in myapp/__init__.py
1 2 3 4 5 6 7 8 9 10 11 |
# ourapp/__init__.py from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy app = Flask(__name__, instance_relative_config=True) app.config.from_object('config') app.config.from_pyfile('config.py') db = SQLAlchemy(app) |
We’re going to use an instance folder for our database configuration so we should use the instance_relative_config option when initializing the app and then call app.config.from_pyfile to load it. Then we can define our models.