注:原文作者 John Kevin M. Basco,原文地点为 Building a blog using Flask and AngularJS Part 1
在这个教程中,我们将运用 Flask 和 AngularJS 构建一个博客。
这是这个系列教程的第一部份,在这部份我们将专注于构建 REST API ,该 API 将被 AngularJS 运用运用。
目的
该运用的目的异常简朴:
- 许可任何用户注册
- 许可注册的用户登录
- 许可登录的用户建立博客
- 许可在首页展现博客
- 许可登录的用户退出
这个运用在该系列教程的末了应当看起来像如许:
必要条件
该教程假定你能顺畅的写 Python 的代码,晓得如何设置一个虚拟环境以及熟习终端窗口
目次构造
我们将运用的目次构造应当看起来像如许:
装置必要的 Python 包
我们将运用的包以下:
- Flask-RESTful – Flask 的 RESTful 扩大
- Flask-SQLAlchemy – Flask 的 SQLAlchemy 扩大
- Flask-Bcrypt – Flask 的 一个为你的运用供应 bcrypt 哈希的东西扩大
- Flask-HTTPAuth – 一个为 Flask 路由供应 Basic and Digest HTTP authentication 的扩大
- Flask-WTF – http://docs.jinkan.org/docs/flask-wtf/
- WTForms-Alchemy – 一个 WTForms 扩大,能很简朴的基于表单建立模子的东西集
- marshmallow – 是一个 ORM/ODM/ 的框架,用于转换庞杂的数据范例,http://marshmallow.readthedocs.org/en/latest/quickstart.html
为了使事变越发简朴,在 blog/server/ 目次下建立一个名称为 requirements.txt 的文件,而且把以下内容拷贝进去:
Flask==0.10.1
Flask-Bcrypt==0.6.0
Flask-HTTPAuth==2.2.1
Flask-RESTful==0.2.12
Flask-SQLAlchemy==1.0
Flask-WTF==0.10.0
Jinja2==2.7.3
MarkupSafe==0.23
SQLAlchemy==0.9.7
SQLAlchemy-Utils==0.26.9
WTForms==2.0.1
WTForms-Alchemy==0.12.8
WTForms-Components==0.9.5
Werkzeug==0.9.6
aniso8601==0.83
decorator==3.4.0
infinity==1.3
intervals==0.3.1
itsdangerous==0.24
marshmallow==0.7.0
py-bcrypt==0.4
pytz==2014.4
six==1.7.3
validators==0.6.0
wsgiref==0.1.2
进入 blog/server/ 目次,而且运转 pip install -r requirements.txt
敕令来装置必需的包
运用的初始化设置
起首,在 blog/server/app 目次下建立一个文件并命名为 config.py,然后复制和粘贴以下的内容到文件中:
DEBUG = True
WTF_CSRF_ENABLED = False
然后在 blog/server/app/ 目次下建立一个文件命名为 server.py。这就是我们将安排我们初始的代码的处所。复制和粘贴以下的代码到文件中:
import os
from flask import Flask
from flask.ext import restful
from flask.ext.restful import reqparse, Api
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.bcrypt import Bcrypt
from flask.ext.httpauth import HTTPBasicAuth
basedir = os.path.join(os.path.abspath(os.path.dirname(__file__)), '../')
app = Flask(__name__)
app.config.from_object('app.config')
# flask-sqlalchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'app.sqlite')
db = SQLAlchemy(app)
# flask-restful
api = restful.Api(app)
# flask-bcrypt
flask_bcrypt = Bcrypt(app)
# flask-httpauth
auth = HTTPBasicAuth()
@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
return response
import views
在这个文件中,我们初始化了 Flask,加载了从一个配置文件中加载了配置文件的变量,建立了 flask-sqlalchemy,flask-restful 对象等等。。。而且我们也在 after_request 函数中加了一些相应头,它许可跨域资本共享(CORS),这将许可我们的托管效劳器(REST API)和客户端(AngularJS app)在差别的域以及差别的子域(比方:api.johnsblog.com 和 johnsblog.com)。在开辟时期,这将许可我们把它们运转在差别的端口(比方:localhost:8000 和 localhost:5000)。
Models
如今我们已完成了运用的初始化部份,让我们定义 models,在 blog/server/app/ 目次下建立一个文件并命名为 models.py,然后拷贝和粘贴以下代码到文件中:
from flask import g
from wtforms.validators import Email
from server import db, flask_bcrypt
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), unique=True, nullable=False, info={'validators': Email()})
password = db.Column(db.String(80), nullable=False)
posts = db.relationship('Post', backref='user', lazy='dynamic')
def __init__(self, email, password):
self.email = email
self.password = flask_bcrypt.generate_password_hash(password)
def __repr__(self):
return '<User %r>' % self.email
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(120), nullable=False)
body = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
created_at = db.Column(db.DateTime, default=db.func.now())
def __init__(self, title, body):
self.title = title
self.body = body
self.user_id = g.user.id
def __repr__(self):
return '<Post %r>' % self.title
在以上的代码中,我们定义了一个用户和文章的模子,用户模子有一个 id
作为它的主键,被定义成 integer 范例,email
和 password
属性被定义成 strings。经由过程 posts
属性它也和 POST 模子有关联。POST 模子也有一个 id
作为它的主键,并也被定义成 integer,title
和 body
属性被定义成 strings。它也有一个 user_id
属性被定义成 integer 并作为 User 模子的 id 属性的外键。它还有一个 created_at
属性被定义成 DateTime。
Forms
如今我们已完成了模子定义部份,让我们定义 forms,我们将运用 forms 校验我们的用户输入。为了 form 校验,我们将运用是一个名称为 WTForms 的 Flask 扩大,而且我们将运用 WTForms-Alchemy 扩大它 来更快更简朴的定义我们的 forms。在 blog/server/app 目次下建立一个新文件并命名为 forms.py,然后拷贝和粘贴以下代码到文件中:
from flask.ext.wtf import Form
from wtforms_alchemy import model_form_factory
from wtforms import StringField
from wtforms.validators import DataRequired
from app.server import db
from models import User, Post
BaseModelForm = model_form_factory(Form)
class ModelForm(BaseModelForm):
@classmethod
def get_session(self):
return db.session
class UserCreateForm(ModelForm):
class Meta:
model = User
class SessionCreateForm(Form):
email = StringField('name', validators=[DataRequired()])
password = StringField('password', validators=[DataRequired()])
class PostCreateForm(ModelForm):
class Meta:
model = Post
为了使得 WTForms-Alchemy 能与 Flask-WTF 一同事情,我们定义了一个类命名为 ModelForm,它继续自 BaseModelForm ,由 WTForms-Alchemy 供应。你能够在这里找到更多的信息 – http://wtforms-alchemy.readthedocs.org/en/latest/advanced.html#using-wtforms-alchemy-with-flask-wtf
以上代码是异常圆满的。然则假如你不明白以上代码做了什么,我发起你读 WTForms 的文档 https://wtforms.readthedocs.org/en/latest/# 和 WTForms-Alchemy 的文档 http://wtforms-alchemy.readthedocs.org/en/latest/index.html 。
Serializers
为了在我们的 responses 中把我们的 model 实例渲染成 JSON,我们起首须要把它们转换成原生的 Python 数据范例, Flask-RESTful 能够运用 fields 模块 和 marshal_with() 装潢器(更多的详细信息请移步 – http://flask-restful.readthedocs.org/en/latest/quickstart.html#data-formatting)。当我最先构建 REST API 的时刻我不晓得 Flask-RESTful 支撑这个,因而我以 Marshmallow 完成 http://marshmallow.readthedocs.org/en/latest/ 。在 blog/server/app/ 目次下建立一个新文件并命名为 serializers.py,然后拷贝和粘贴以下代码到文件中:
from marshmallow import Serializer, fields
class UserSerializer(Serializer):
class Meta:
fields = ("id", "email")
class PostSerializer(Serializer):
user = fields.Nested(UserSerializer)
class Meta:
fields = ("id", "title", "body", "user", "created_at")
Views
如今我们已完成了我们将运用的 models,forms 和 serializers 的定义,让我们定义 views 而且运用。在 blog/server/app/ 目次下建立一个新文件并命名为 views.py ,然后拷贝和粘贴以下代码到文件中:
from flask import g
from flask.ext import restful
from server import api, db, flask_bcrypt, auth
from models import User, Post
from forms import UserCreateForm, SessionCreateForm, PostCreateForm
from serializers import UserSerializer, PostSerializer
@auth.verify_password
def verify_password(email, password):
user = User.query.filter_by(email=email).first()
if not user:
return False
g.user = user
return flask_bcrypt.check_password_hash(user.password, password)
class UserView(restful.Resource):
def post(self):
form = UserCreateForm()
if not form.validate_on_submit():
return form.errors, 422
user = User(form.email.data, form.password.data)
db.session.add(user)
db.session.commit()
return UserSerializer(user).data
class SessionView(restful.Resource):
def post(self):
form = SessionCreateForm()
if not form.validate_on_submit():
return form.errors, 422
user = User.query.filter_by(email=form.email.data).first()
if user and flask_bcrypt.check_password_hash(user.password, form.password.data):
return UserSerializer(user).data, 201
return '', 401
class PostListView(restful.Resource):
def get(self):
posts = Post.query.all()
return PostSerializer(posts, many=True).data
@auth.login_required
def post(self):
form = PostCreateForm()
if not form.validate_on_submit():
return form.errors, 422
post = Post(form.title.data, form.body.data)
db.session.add(post)
db.session.commit()
return PostSerializer(post).data, 201
class PostView(restful.Resource):
def get(self, id):
posts = Post.query.filter_by(id=id).first()
return PostSerializer(posts).data
api.add_resource(UserView, '/api/v1/users')
api.add_resource(SessionView, '/api/v1/sessions')
api.add_resource(PostListView, '/api/v1/posts')
api.add_resource(PostView, '/api/v1/posts/<int:id>')
上面的 verify_password 函数被 auth.verify_password 装潢,并将被 Flask-HTTPAuth 运用来审定用户。它基本上经由过程 email 来猎取用户,以及经由过程校验给出的暗码是不是与数据库中存储的暗码婚配。
UserView 类将处置惩罚用户的注册请求,SessionView 类将处置惩罚用户的登录请求,PostListView 将处置惩罚猎取文章列表和建立文章的请求。末了,PostView将处置惩罚猎取单篇文章的请求。在文件的底部,我们简朴的设置了 API 的资本路由。
建立数据库
我们也须要建立一个名称为 db_create.py 的文件。我们将运转这个脚原本初始化数据库。如今我们将进入 blog/server/ 目次并运用 python db_create.py
运转这个剧本。
from app.server import db
db.create_all()
运转 REST API 效劳
我们须要建立的别的一个文件是 run.py。这是一个剧本,我们将经由过程运转它来运转一个 REST API 效劳。
from app.server import app
app.run()
假如你准确的遵照了以上步骤,你如今应当能够经由过程进入 blog/server/ 目次并运转 python run.py
来运转 REST API 效劳。
完毕点
注册一个用户
为了注册一个用户你须要发送一个 POST 请求给 localhost:5000/api/v1/users。这个请求属性是 email 和 password。这里有 curl 请求来建立一个用户
curl --dump-header - -H "Content-Type: application/json" -X POST -d '{"email": "johndoe@gmail.com","password": "admin"}' http://localhost:5000/api/v1/users
上岸一个用户
为了上岸一个用户,你须要经由过程运用 POST 请求发送一个用户的上岸资历给 localhost:5000/api/v1/sessions。示例:
curl --dump-header - -H "Content-Type: application/json" -X POST -d '{"email": "johndoe@gmail.com","password": "admin"}' http://localhost:5000/api/v1/sessions
建立一篇文章
为了建立一篇文章,你须要发送一个 POST 请求给 localhost:5000/api/v1/posts。须要的属性是 title 和 body。由于建立文章的时刻请求用户是已上岸的,注重你须要发送一个包括 base64 编码的用户资历的 Authorization header ,它是经由过程冒号(”:”)星散的。示例:
curl --dump-header - -H "Content-Type: application/json" -H "Authorization: Basic am9obmRvZUBnbWFpbC5jb206YWRtaW4=" -X POST -d '{"title": "Example post","body": "Lorem ipsum"}' http://localhost:5000/api/v1/posts
猎取文章
为了猎取一切保留的文章,你须要发送一个 GET 请求给http://localhost:5000/api/v1/posts 。示例:
curl -i http://localhost:5000/api/v1/posts
除了运用 curl,你也能够运用更高等的 REST 客户端 Chrome 扩大来测试 API。
下一步?
该教程的第一部份到这里就完毕了。在教程的第二部份,我们将专注于构建一个 AngularJS web 运用,它将挪用我们已建立的 REST api。
假如你发现了这篇文章的一些毛病或是你有一些问题想问,请在下面留下你的批评。
我愿望你喜好该教程的一部份。在教程的第二部份见。
可用的 REST API 源码在 Github 上,假如你喜好这个教程,而且它对你有协助,请给星,下载和 fork 它 – https://github.com/basco-johnkevin/building-a-blog-using-flask-and-angularjs
你也能够在 Twitter 上关注我 – https://twitter.com/johnkevinmbasco