Flask Vue.js全栈开发|第3章:Flask设计User用户相关API
Synopsis: Flask 后端针对 "用户资源" 提供部分 RESTful API,基于 token 认证,目前支持添加用户、查看单个或多个用户、修改用户,使用 HTTPie 或 Postman 测试 API 通过。下一篇将在前端使用这些 API 实现用户注册、登录与退出功能
代码已上传到 https://github.com/wangy8961/flask-vuejs-madblog/tree/v0.3 ,欢迎star
1. git
1.1 从 Github 拉取最新代码
$ git remote -v origin git@github.com:wangy8961/flask-vuejs-madblog.git (fetch) origin git@github.com:wangy8961/flask-vuejs-madblog.git (push) $ git fetch 或者,拉取指定的远程主机上的分支,比如 origin 上的 master 分支 $ git fetch origin master
1.2 创建 dev 分支
2. 数据库
2.1 ORM: SQLAlchemy
安装 Flask-SQLAlchemy
插件,还有数据表结构有变化后进行迁移的 Flask-Migrate
插件
(venv) D:\python-code\flask-vuejs-madblog\back-end>pip install flask-sqlalchemy flask-migrate (venv) D:\python-code\flask-vuejs-madblog\back-end>pip freeze > requirements.txt
修改配置文件 back-end/config.py
,默认使用 SQLite
数据库:
import os from dotenv import load_dotenv basedir = os.path.abspath(os.path.dirname(__file__)) load_dotenv(os.path.join(basedir, '.env')) class Config(object): SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'app.db') SQLALCHEMY_TRACK_MODIFICATIONS = False
修改 app/__init__.py
,引入并初始化插件:
from flask import Flask from flask_cors import CORS from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from config import Config # Flask-SQLAlchemy plugin db = SQLAlchemy() # Flask-Migrate plugin migrate = Migrate() def create_app(config_class=Config): app = Flask(__name__) app.config.from_object(config_class) # Enable CORS CORS(app) # Init Flask-SQLAlchemy db.init_app(app) # Init Flask-Migrate migrate.init_app(app, db) # 注册 blueprint from app.api import bp as api_bp app.register_blueprint(api_bp, url_prefix='/api') return app
2.2 定义 User 用户数据模型
创建 app/models.py
:
from app import db class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), index=True, unique=True) email = db.Column(db.String(120), index=True, unique=True) password_hash = db.Column(db.String(128)) # 不保存原始密码 def __repr__(self): return '<User {}>'.format(self.username)
修改 app/__init__.py
,在文件末尾添加:
2.3 第一次数据库迁移
(1) 创建迁移存储库
(2) 生成迁移脚本
(3) 将迁移脚本应用到数据库中
说明:
flask db downgrade
命令可以回滚上次的迁移
2.4 存储用户密码的 hash 值
使用 werkzeug.security
库的 generate_password_hash
和 check_password_hash
来创建哈希密码和验证密码的hash是否一致:
(venv) D:\python-code\flask-vuejs-madblog\back-end>python Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 17:54:52) [MSC v.1900 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> from werkzeug.security import generate_password_hash, check_password_hash >>> hash = generate_password_hash('foobar') >>> hash 'pbkdf2:sha256:50000$Z39YZhom$2a59a7a0edf67db5e29632134cb1fbbfec55077a262c659de662dbe5de623329' >>> check_password_hash(hash, 'foobar') True >>> check_password_hash(hash, 'barfoo') False >>>
更新 User 数据模型:
from werkzeug.security import generate_password_hash, check_password_hash from app import db class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), index=True, unique=True) email = db.Column(db.String(120), index=True, unique=True) password_hash = db.Column(db.String(128)) # 不保存原始密码 def __repr__(self): return '<User {}>'.format(self.username) def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password)
配置 Flask Shell 上下文环境:
flask shell
命令是 flask
命令集中的另一个非常有用的工具,它是继 flask run
之后被实现的第二个 "核心" 命令,其目的是启动一个Python解释器包含应用的上下文
(venv) D:\python-code\flask-vuejs-madblog\back-end>flask shell Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)] on win32 App: app [production] Instance: D:\python-code\flask-vuejs-madblog\back-end\instance >>> app <Flask 'app'> >>> db Traceback (most recent call last): File "<console>", line 1, in <module> NameError: name 'db' is not defined
修改 back-end/madblog.py
,添加一个方法:
from app import create_app, db from app.models import User app = create_app() @app.shell_context_processor def make_shell_context(): return {'db': db, 'User': User}
再次运行 flask shell
命令:
(venv) D:\python-code\flask-vuejs-madblog\back-end>flask shell Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)] on win32 App: app [production] Instance: D:\python-code\flask-vuejs-madblog\back-end\instance >>> app <Flask 'app'> >>> db <SQLAlchemy engine=sqlite:///D:\python-code\flask-vuejs-madblog\back-end\app.db> >>> User <class 'app
27 条评论
评论者的用户名
评论时间Erhei0281
2019-06-29T11:51:29Z请问app.api下的auth教程是漏掉了吗?
Madman Author
2019-06-29T11:57:48Z请按照git代码仓库的tag阅读教程对应的每一章代码,auth.py是第五章时API的认证改为jwt了才需要
用户认证修改为 JWT(JSON Web Token),后端使用 pyjwt 库生成 JWT 并验证合法性;前端使用 JSON.parse 解析 JWT 中的 payload 数据
Erhei0281 Madman
2019-06-29T13:45:42Z了解,谢谢!
Erhei0281
2019-06-29T14:20:25Z目前我遇到的问题就是:第二次db upgrade报错,内容显示duplicate column name: token.
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) duplicate column name: token [SQL: ALTER TABLE user ADD COLUMN token VARCHAR(32)]
Madman Erhei0281 Author
2019-06-29T14:33:51Z先删除app.db再试
Erhei0281 Madman
2019-06-30T07:56:59Z已经解决,谢谢。
s1riu5
2019-12-05T08:33:20Zflask-sqlalchemy是依赖于上下文,那如果想用threading.Thread启用心跳线程的话该怎么解决
vow
2020-02-07T03:14:21Z本教程3.5中应该删了<font color="red">from app.api.auth import token_auth</font>这一句,
否则报错: ModuleNotFoundError: No module named 'app.api.auth'
应该是后面的教程会写一个auth,楼主忘删了,不应该在此处出现
Madman vow Author
2020-02-07T03:53:18Z见本文的 4.4 HTTP Token Authentication
kanouakira
2020-02-20T17:34:51Z刚开始学习,只把数据库改成了MySQL,到了flask shell 这步还是会出现
请教这是为什么呢?
Madman kanouakira Author
2020-02-21T00:11:19Z学习时不要浮躁要仔仔细细看文章并理解透,你的
.env
文件名对吗?里面的环境变量名FLASK_APP
对吗? 越是新手,越要培养自己解决问题的能力,先google或Bing搜索(搜索也有技巧的,别人搜得到你不一定搜得到,自己查攻略),像这个问题搜索结果大把。实在解决不了再提问,涉及代码等用markdown格式会清楚很多。如果问题解决后,要记笔记!雪中剑来
2020-03-02T03:20:19Z注册用户一直出这个错误
请问是什么问题?
POST http://localhost:5000/api/users username=alice password=123456 email=alice@163.com
Madman 雪中剑来 Author
2020-03-02T03:22:46Z数据库
users
表中已经有同样的用户名或 Email 地址的用户存在了,需要删除它或用其它用户名。可以用Navicat Premium 12
图形界面工具查看数据库信息雪中剑来
2020-03-04T10:45:37Z按照流程走我迁移完成然后注册用户完成,应该会有数据保存在数据库的表中,我用图形化工具查看mysql里面确没有数据和表呢?
Madman 雪中剑来 Author
2020-03-04T13:47:35Z默认使用
SQLite
数据库,文件为当前路径下的app.db
:所以,请仔细检查配置文件
config.py
或.env
皓月qhy
2020-03-30T09:12:01Z我想问一下为什么 errors 要把那些错误额外写error_handler呢?
xankegongge
2020-07-12T02:26:53Z老师的内容很棒,有收获
mangwu
2020-08-06T08:30:05Z在4.6 撤销 Token代码中,我的一直提示返回值类型错误,是什么原因?
mangwu mangwu
2020-08-06T08:40:42Z已解决,是我利用上下键修改请求内容,没有认真看DELET请求的localhost地址导致
用户7206094097
2022-11-16T06:30:21Z通过post提交后端数据出现{"error": "Bad Request"}
用户7206094097 用户7206094097
2022-11-16T06:41:55Z已解决,把message打印出来看一下就知道了
用户7206094097
2022-11-18T14:50:20Zpage = request.args.get('page', 1, type=int) per_page = min(request.args.get('per_page', 10, type=int), 100)这两句不太理解
Madman 用户7206094097 Author
2022-11-22T01:55:26Z这个是获取 URL 的查询参数(比如 http://madmalls.com/blog/post-list/?page=1&per_page=10),从后台获取数据一般要分页(数据量太多)
page = request.args.get('page', 1, type=int)
表示当前要获取第几页,参数名为 page,flask 需要默认给我转成类型为 int,如果前端没传 page 这个查询参数、那么默认值赋值为 1用户7206094097 Madman
2022-11-24T01:22:18Z感谢up主
用户7206094097
2022-11-24T03:09:05Zdef revoke_token(self): self.token_expiration = datetime.utcnow() - timedelta(seconds=1)
def revoke_token(): g.current_user.revoke_token() db.session.commit() return '', 204
token_expiration在get_token函数不是已经创建了吗,为什么还要再定义一次 还有两个revoke_token()是一样的吗
mingyun
2023-03-02T06:17:57Zhttp://127.0.0.1:5000/api/users ['GET']返回用户集合时报 TypeError: Query.paginate() takes 1 positional argument but 4 were given
luohuai1Q84 mingyun
2023-06-01T06:54:32Zhttps://stackoverflow.com/questions/74144613/flask-sqlalchemy-raises-typeerror-query-paginate-takes-1-positional-argument