flask学习笔记

flask

运行流程

  1. creat一个app对象,通过Flask(name)来注册方法,然后run_app

  2. 通过flask_script将app注册到manager 可以自定义一些其他的command manager=Manager(app)

  3. 在creat_app方法中注册app的一些功能模块

    moment=Monment() moment.init_app(app)

  4. app.register_blueprint() 注册蓝图:

    auth_blueprint=Blueprint('sd', _ name _)

    app.register_blueprint(auth_blueprint, url_prefix='/auth')

博客项目

将程序实例的创建推迟到配置文件的载入后
推迟到工厂函数中

app=Flask(name) app的名称

app.config 加载配置文件
使用蓝本来处理路由
. 从init.py 中引入

  • 避免循环导入依赖的方法 依赖放在最后面

密码

通过散列来保存密码
通过设置属性来调用方法

  • 通过使用itsdangerous生成确认令牌
    包含用户id,感觉和散列有点像

必须先提交数据库,然后再邮件认证

用户

认证

注册先存入数据库,然后根据数据库返回的序列号生成一个链接,email发送,如果点击链接,跳转到函数,让数据库中is_confirmed那项为true

如果没认证,每次登陆都跳转到index页面

  • 通过token 来得到data,data是一个字典类型
    然后 data.get(id)来得到用户的序号

_external=True 参数在
url_for()中 的路由的参数是函数的名字

  • 通过before login 来确定是否认证,如果没认证就跳转到认证页面

用户登录

让数据库 User models 增加 userMinxin from flask_login导入的。

  • 从view页面得到当前user的数据库模型,user.get_or_create(id)

重置密码:

两种重置密码方式

一种是登录的情况下,一种是非登录的情况下,都应该邮件确认,保证安全

和邮件认证用户一个道理,但不同的是,这个token中要包含用户的信息,那个token是固定的密码.

所以这个token解密后应该是 包含用户信息的。

token的有效载荷是固定的,不能被伪造。 有效载荷中包含用户的信息以及秘钥的信息

{'reset_password':user_id,'exp':token_expiration}

python2.7用serilize包, 把需要添加的值dump进去

需不需要一个实用的工具包

来处理琐碎的事情

比如说生成密码token,发送邮件什么的。

反正发送邮件要交给后台来处理

pip

安装到某个文件夹下的txt中
pip install -r requirements/dev.txt

测试

单元测试
文件都写在tests文件夹下

在manage.py中写的命令
@manager.command
def test():
import unittest
tests = unittest.TestLoader().discover('tests')
unittest.TextTestRunner(verbosity=2).run(tests)

  • python manage.py test

操作权限

关注用户:1
发表评论:2
写文章:4
管理评论:8
管理员权限:128

用户权限

用户的等级
匿名:0
正式用户:7
协管员:15
管理员:255

current_user方法

is_anonymous 判断是否是匿名用户

蓝本

来处理路由,不同的功能使用不同的蓝本
相当于django中的分开处理路由

在工厂函数中注册蓝本,相当于django在主页面的Url添加辅助功能的url

template

template中可以读取txt路径,作为html的内容

路径问题

模板的路径是相对于程序模板文件夹来说的

base中auth.logout对应的是方法名,而不是路径名

方法名和路径名好像必须要一样。。。

在html中添加动态路径

路由跳转

接受函数名作为参数

url_for('main.user',username=current_user.username)

return redirect(url_for('main.user',username=current_user.username))

flask-login

将login_manager添加在login中
LoginManager 对象的 session_protection 属性可以设为 None、'basic' 或 'strong',以提 供不同的安全等级防止用户会话遭篡改。设为 'strong' 时,Flask-Login 会记录客户端 IP 地址和浏览器的用户代理信息,如果发现异动就登出用户
表单: user email password remember submit

数据库

sqlalchemy

用来更新Model表的参数

类型于django migration 和migrate

  • 初始化 创建migrations文件夹
    python manage.py db init

  • 迁移 相当于django中的migrate
    python manage.py db migrate -m 'second migrate'

  • 实际迁移到数据库中 相当于django makemigraions
    python hello.py db upgrade

  • event sqlalchemy set 时间的监听程序,只要进行了set 就会调用on_changed_body函数
    on_change_body函数将markdown渲染为html,然后返回

联结操作

在文章页面只显示用户关注用户的文章
Post.join(Follow,Follow.follow_id==Post.author.id)

相关知识

  • 主键是不唯一的

  • casacde 级联删除的意思,当删除外键依赖的主表时,子表内容自动删除

api

  • order_by.all()
  • filter_by().first()
  • 对主键进行查找 .get_or_404()

分页

  • query.order_by(Post.timestamp.desc()).paginaton()
    分页的属性:
  • items 查询到的记录
  • query 源查询
  • page 当前页数
  • prev_num 上一页的页数
  • next_num 下一页的页数
  • has_next 是否有上一页
    -has_prev 是否有上一页
  • pages 总页数
  • per_page 每页的记录数量
  • total 记录总数、

在对象上调用的方法
iter_pages 迭代器,返回一个页数列表

写好一个分页页面, _macros,然后在其他需要分页的html中将这个页面插入

alembic

  • 初始化
mbic init YOUR_ALEMBIC_DIR

relationship

关系之间的便捷调用

Student model:
classes=db.relationship('class',secondary=restrations,backerf=db.backref('students',lazy='dynamic'),
lazy='dynamic')

student的clsses属性和class表建立relationship,
同时提供一个反向声明, class表中的对象可以直接classe.students来筛选出选了该课的学生

flask中session操作

  • 增加 和更新

db.session.add(user)

db.session.commit()

  • 删除

    db.session.delete(user)

    db.session.commit()

查询方式

主键查询
receive_user=User.query.filter_by(username=recepient).first_or_404()
receive_user=User.query.get_or_404(id)
其他条件查询:
receive_user=User.query.filter_by(username=recepient).first()


多对多的关系

两个表对一个辅助表建立外键索引,然后根据约束来查找
比如:
class 和student 再建立一张表:sdu_class, 表中的属分别和两个子表建立索引关系

具体实现

通过 两个表建立relationship 同时在relationship中声明secondary实现many to many

自引用

上面的学生和老师有两个实体

如果是用户和用户之间,那么只有一个关系。
一个实体之间的多对多称为自引用

给用户添加两个属性
follower和followed

要额外储存两个实体间的额外信息,比如关注者的关注日期

建立一个新的表,同时在user中添加,followed和follwer 和follow表建立自引用

lazy

lazy决定了什么时候从数据库中加载数据
lazy的三个参数
dynamic joined select
dynamic 应该是relationship被调用时返回一个query()对象
joined relationship被调用时返回两个表join的结果值
select 是访问到属性时,会加载全部的属性。

backref

第一个字段是表的名称,第二个字段是给第一个字段表中调用的别名

post=db.relationship('Post',backref='author',lazy='dynamic)

backref提供反向声明
user和post形成一对多的关系,一个user可以生产多个post
Post在找user时可以根据author直接找到,而不需要再根据author_id在User中查找

back_populates

和backref的不同点,在于back_populates是显式声明了关系的应用

版本迁移 迁移脚本中的函数

  • current 查看当前版本的信息
  • upgrade upgrade() 函数把迁移中的改动应用到数据库中
  • downgrade() 函数则将改动 删除。

回退

数据库根据 migrations 回退的方法

downgrade后删除一个版本的函数就好

  • 增加用户
    db.session.add(user)

db shell

from app.models import *

Role.insert_roles()

date

date.utcnow 没有括号,default可以接受函数作为参数

连接mysql

dir=mysql://root@localhost:3306/hello_flask?charset=utf8mb4


解决bug

  • 配置名必须大写...

  • TypeError: init() takes at most 2 arguments (3 given) form表格中没有添加路径

  • 书中的bug
    在User model中的is_following(user)方法中,检查当前用户是否关注了user用户,应该用self.followed.filter_by(follower=user)
    self.followed为current_user关注的所有人的集合,在这个集合中,所有的followed项都为current_user,所有的follower项为各个被关注的用户,所以要找出是否关注了某个用户,应该是,
    self.followed.filter_by(follower=user)

View

bootstrap

<div class="col-md-4">
限制了内容的长度

jinjia

safe 标签,告诉jinjia 不要转义html标签

问题

为什么在分页筛选中得不到自己关注自己的那个结果
解决:在follower.html中设置一下。。

评论

一个文章有多个评论。属于一对多关系
一个用户能发表多个评论,然后文章可以有多个评论

在user和post中添加relationship和comment关联

在文章的Index页面每篇文章下显示comment数量,
然后点击可以进入查看post发表文章的主界面,
在主界面下有文章的所有评论,评论的发表时间以及,详细日期

restful api

  • 因为是无状态的,又要经过客户端验证,所以用http-auth

进行httpie测试

http --json --auth fjl2401@163.com:cat GET http://127.0.0.1:5000/api/posts

http --json --auth eyJhbGciOiJIUzI1NiIsImV4cCI6MTUyNjk1MjM4MCwiaWF0IjoxNTI2OTQ4NzgwfQ.eyJpZCI6MX0.K97b2cUxBU4cqCI63IwFCgzYpMVMre7BRfqXP-6yVmU: GET http://127.0.0.1:5000/api/v1.0/posts/

g.current_user

g.current_user的初始化在before_request那里

所以在请求api时会出现错误是因为在初始化时没有加入before_request()

http状态码

200 响应成功

201 创建成功

202 接受

301 Moved Permanently 永久的移动了

项目部署 和环境

https://icecola.herokuapp.com/ | https://git.heroku.com/icecola.git

运行

python hello.py runserver --host 0.0.0.0

连接数据库:

musql :mysql://username:password@localhost/database

postgresql://username:password@localhost/database

sqlite : sqlite:///absolute/path/to/databse

部署gunicorn

将flask部署在5001端口上

gunicorn -b 0.0.0.0:5001 -w 4 manage:app

gunicorn -b localhost:5000 -w 4 hello_flask:app

supervisor 来部署gunicorn

supervisor 进程管理工具

~/django_1/VENV_flask/hello_flask

利用supervisor来监视进程,在进程死亡后拉起

sudo mkdir /etc/supervisor

sudo echo_supervisord_conf > /etc/supervisord.conf 生成配置文件

查看默认配置文件

查看supervisord是否在运行

ps aux | grep supervisord

echo_supervisord_conf

  • 启动服务
supervisord -c /etc/supervisor/supervisord.conf
运行自己写的配置文件:
supervisord -c /etc/supervisor/conf.d/hello_flask.conf



使用 supervisorctl

Supervisorctl 是 supervisord 的一个命令行客户端工具,启动时需要指定与 supervisord 使用同一份配置文件,否则与 supervisord 一样按照顺序查找配置文件。

进入客户端

supervisorctl -c /etc/supervisord.conf
 supervisorctl -c /etc/supervisor/conf.d/hello_flask.conf
  • 进入之后

    • status 查看状态
    • reread 重新启动
    • restart program_name 重启某个项目
    • stop all 停止所有
    • update 更新
  • 启动某个进程

    supervisorctl starprogram_name

    重新加载

    supervisorctl reload

配置了http服务后的启动 sudo supervisorctl -u chris -p 123

  • gunicorn直接启动命令

    /home/ubuntu/django_1/VENV_flask/bin/gunicorn -b localhost:5000 -w 4 hello_flask:app

​conf文件的配置

[program:hello_flask ]

command=/home/ubuntu/django_1/VENV_flask/bin/gunicorn -b localhost:5000 -w 4 hello_flask:app

directory=/home/ubuntu/django_1/VENV_flask/hello_flask

user=ubuntu

autostart=true

autorestart=true

stopasgroup=true

killasgroup=true

stdout_logfile=/home/ubuntu/django_1/VENV_flask/hello_flask/log/out_log.log

stderr_logfile=/home/ubuntu/django_1/VENV_flask/hello_flask/log/err_log.log

[supervisord]

575报错:

关联到nginx
    location {
    # forward application requests to the gunicorn server  

    proxy_pass http://localhost:5000;

    proxy_redirect off;

    proxy_set_header Host $host;

    proxy_set_header X-Real-IP $remote_addr;

    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}

location /static {

    # handle static files directly, without forwarding to the application

    alias /home/ubuntu/django_1/VENV_flask/hello_flask/app/static;

    expires 30d;

}

# write access and error logs to /var/log

access_log /var/log/hello_flask_access.log;

error_log /var/log/hello_flask_error.log;
}

部署到heroku

登录

heroku login

输入在官网注册的账户和 密码

创建应用

heroku create <appname> 名字可以自己选

heroku create --buildpack heroku/python

Creating heroku-postgresql on ⬢ floating-ravine-41608... free
https://floating-ravine-41608.herokuapp.com/ | https://git.heroku.com/floating-ravine-41608.git

添加数据库

heroku addons:create heroku-postgresql -a floating-ravine-41608

Database has been created and is available
! This database is empty. If upgrading, you can transfer
! data from another database with pg:copy
Created postgresql-parallel-90394 as DATABASE_URL
Use heroku addons:docs heroku-postgresql to view documentation

显示git和网页地址

git remote show heroku

进入数据库

heroku pg:psql -a floating-ravine-41608

DATABASE_URL: postgres://xriuxrfpqtfmpj:f10a0a38f76e0e2be3bc52e69aa477d161736775976c93ce6e0470bce8c92d82@ec2-107-21-126-193.compute-1.amazonaws.com:5432/d9uqv1edl13ka8

如果运行git push heroku出错,运行这步

heroku git:remote -a floating-ravine-41608

push上去 即可运行

git push heroku master

部署flask 需要的文件

runtime.txt 表示运行时的python环境
python-2.7.14
requirements.txt 用 pip freeze > requirements.txt 生成
Flask==0.10.1
Flask-SQLAlchemy==2.0
Flask-WTF==0.12
Jinja2==2.8
MarkupSafe==0.23
SQLAlchemy==1.0.8
WTForms==2.0.2
Werkzeug==0.10.4
click==4.1
decorator==4.0.2
geocoder==1.4.1
gunicorn==19.3.0
itsdangerous==0.24
psycopg2==2.7.3.1
ratelim==0.1.6
requests==2.7.0
six==1.9.0
wsgiref==0.1.2
Procfile 显示路由的app和 运行的服务器
web: gunicorn routes:app
.env.env 配置环境变量 ,heroku会直接从这里读取
FLASK_APP=flasky.py
FLASK_CONFIG=heroku
MAIL_USERNAME=fjl2401
MAIL_PASSWORD=youpass

添加后台任务

在views中用current_user来调用,实现跳转到models的方法

用rq来处理,在models.user中定义launch方法,实现跳转到current_app的队列

然后通过rq_job这个名字自动加入到消息队列中,任务的名称为name+user.id

在app的init中 任务队列初始化,连接到redis服务器

在当前目录下找tasks这个文件,然后根据 views传进来的名称来定位到对于的目录下的py文件的函数名,

运行对应的函数。

在指定name任务队列中分配worker,保证该任务队列有worker

然后实例化一个队列对象

queue = rq.Queue('new_work', connection=Redis.from_url('redis://'))

将方法添加到队列生成job

job = queue.enqueue('app.tasks.example', 23)

rabbit-rmq

地址

http://localhost:15672/

用户名和密码 guest

启动: ./rabbitmq-server

ps -ef|grep rabbit

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348

推荐阅读更多精彩内容