creat一个app对象,通过Flask(name)来注册方法,然后run_app
通过flask_script将app注册到manager 可以自定义一些其他的command manager=Manager(app)
在creat_app方法中注册app的一些功能模块
moment=Monment() moment.init_app(app)
app.register_blueprint() 注册蓝图:
auth_blueprint=Blueprint(‘sd’, _ name _)
app.register_blueprint(auth_blueprint, url_prefix=’/auth’)
将程序实例的创建推迟到配置文件的载入后
推迟到工厂函数中
app=Flask(name) app的名称
app.config 加载配置文件
使用蓝本来处理路由
. 从init.py 中引入
- 避免循环导入依赖的方法 依赖放在最后面
通过散列来保存密码
通过设置属性来调用方法
必须先提交数据库,然后再邮件认证
注册先存入数据库,然后根据数据库返回的序列号生成一个链接,email发送,如果点击链接,跳转到函数,让数据库中is_confirmed那项为true
如果没认证,每次登陆都跳转到index页面
_external=True 参数在
url_for()中 的路由的参数是函数的名字
让数据库 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,发送邮件什么的。
反正发送邮件要交给后台来处理
安装到某个文件夹下的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
is_anonymous 判断是否是匿名用户
来处理路由,不同的功能使用不同的蓝本
相当于django中的分开处理路由
在工厂函数中注册蓝本,相当于django在主页面的Url添加辅助功能的url
template中可以读取txt路径,作为html的内容
模板的路径是相对于程序模板文件夹来说的
base中auth.logout对应的是方法名,而不是路径名
方法名和路径名好像必须要一样。。。
接受函数名作为参数
url_for(‘main.user’,username=current_user.username)
return redirect(url_for('main.user',username=current_user.username))
将login_manager添加在login中
LoginManager 对象的 session_protection 属性可以设为 None、’basic’ 或 ‘strong’,以提 供不同的安全等级防止用户会话遭篡改。设为 ‘strong’ 时,Flask-Login 会记录客户端 IP 地址和浏览器的用户代理信息,如果发现异动就登出用户
表单: user email password remember submit
用来更新Model表的参数
类型于django migration 和migrate
- 初始化 创建migrations文件夹
python manage.py db init
实际迁移到数据库中 相当于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 级联删除的意思,当删除外键依赖的主表时,子表内容自动删除
在对象上调用的方法
iter_pages 迭代器,返回一个页数列表
写好一个分页页面, _macros,然后在其他需要分页的html中将这个页面插入
mbic init YOUR_ALEMBIC_DIR
关系之间的便捷调用
Student model:
classes=db.relationship(‘class’,secondary=restrations,backerf=db.backref(‘students’,lazy=’dynamic’),
lazy=’dynamic’)
student的clsses属性和class表建立relationship,
同时提供一个反向声明, class表中的对象可以直接classe.students来筛选出选了该课的学生
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的三个参数
dynamic joined select
dynamic 应该是relationship被调用时返回一个query()对象
joined relationship被调用时返回两个表join的结果值
select 是访问到属性时,会加载全部的属性。
第一个字段是表的名称,第二个字段是给第一个字段表中调用的别名
post=db.relationship(‘Post’,backref=’author’,lazy=’dynamic)
backref提供反向声明
user和post形成一对多的关系,一个user可以生产多个post
Post在找user时可以根据author直接找到,而不需要再根据author_id在User中查找
和backref的不同点,在于back_populates是显式声明了关系的应用
数据库根据 migrations 回退的方法
downgrade后删除一个版本的函数就好
from app.models import *
Role.insert_roles()
date.utcnow 没有括号,default可以接受函数作为参数
dir=mysql://root@localhost:3306/hello_flask?charset=utf8mb4
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)
safe 标签,告诉jinjia 不要转义html标签
为什么在分页筛选中得不到自己关注自己的那个结果
解决:在follower.html中设置一下。。
一个文章有多个评论。属于一对多关系
一个用户能发表多个评论,然后文章可以有多个评论
在user和post中添加relationship和comment关联
在文章的Index页面每篇文章下显示comment数量,
然后点击可以进入查看post发表文章的主界面,
在主界面下有文章的所有评论,评论的发表时间以及,详细日期
进行httpie测试
http –json –auth [email protected]:cat GET http://127.0.0.1:5000/api/posts
创建文章
http –auth [email protected]:cat –json POST http://127.0.0.1:5000/api/posts/ “body=I’m adding a post from the command line.”
使用认证令牌来发送请求
http –auth [email protected]:cat –json GET http://127.0.0.1:5000/api/v1.0/token
在model中的生成令牌的方法:
s = Serializer(current_app.config[‘SECRET_KEY’],expires_in=expiration)return s.dumps({‘id’: self.id}).decode(‘ascii’)
http –json –auth eyJhbGciOiJIUzI1NiIsImV4cCI6MTUyNjk1MjM4MCwiaWF0IjoxNTI2OTQ4NzgwfQ.eyJpZCI6MX0.K97b2cUxBU4cqCI63IwFCgzYpMVMre7BRfqXP-6yVmU: GET http://127.0.0.1:5000/api/v1.0/posts/
g.current_user的初始化在before_request那里
所以在请求api时会出现错误是因为在初始化时没有加入before_request()
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
将flask部署在5001端口上
gunicorn -b 0.0.0.0:5001 -w 4 manage:app
gunicorn -b localhost:5000 -w 4 hello_flask:app
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 是 supervisord 的一个命令行客户端工具,启动时需要指定与 supervisord 使用同一份配置文件,否则与 supervisord 一样按照顺序查找配置文件。
进入客户端
supervisorctl -c /etc/supervisord.conf
supervisorctl -c /etc/supervisor/conf.d/hello_flask.conf
进入之后
启动某个进程
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报错:
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 login
输入在官网注册的账户和 密码
heroku create 名字可以自己选
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
heroku pg:psql -a floating-ravine-41608
DATABASE_URL: postgres://xriuxrfpqtfmpj:f10a0a38f76e0e2be3bc52e69aa477d161736775976c93ce6e0470bce8c92d82@ec2-107-21-126-193.compute-1.amazonaws.com:5432/d9uqv1edl13ka8
python-2.7.14
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
web: gunicorn routes:app
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)
地址
http://localhost:15672/
用户名和密码 guest
启动: ./rabbitmq-server
ps -ef|grep rabbit