flask学习笔记

作者: Colaplusice | 来源:发表于2018-06-28 18:37 被阅读0次

    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

    相关文章

      网友评论

        本文标题:flask学习笔记

        本文链接:https://www.haomeiwen.com/subject/oanrhftx.html