zoukankan      html  css  js  c++  java
  • Flask纪要

    flask学习过程

    1框架基础
    2redis高性能key-value数据库
    3视图具有装饰器的路由函数
    4模板html文件 面向对象操作数据库orm
    5蓝图
    6单元测试
    7GitHub
    8项目

    学习的目的
    1清晰的业务逻辑 2解决bug的能力-->先定位bug 3面向百度变成-->搜索问题的精准程度StackOverflow 4能够灵活应用知识点-->内置函数,列表推导式


    web的本质world wide web 利用互联网进行数据交流
    客户端 浏览器 ios Android发送请求(用户输入,a,img,Ajax,爬虫) 渲染页面
    服务端 服务器脚本->WSGI->应用程序 接收请求 解析请求 路由分发 业务逻辑 返回响应

    使用web框架 的目的 安全性 高并发 提高开发效率 稳定 拓展性强

    框架--协助开发的功能代码-->按照规定的要求 在指定位置上写业务代码

    flask 快速完成项目
    djiango 商城项目完备 齐全
    tornado 异步框架

    flask的wsgi werkzeug-->路由正则 jinja2-->模板的渲染

    虚拟环境 为了在同一台电脑上使每个项目都有属于自己的python环境 不然会造成环境覆盖

    搭建虚拟环境
    sudo pip install virtualenv
    sudo pip install virtualenvwrapper

    创建建python2版本虚拟环境
    mkvirtualenv 环境名 在使用python 在左侧会显示虚拟环境的名字 deacative退出虚拟环境
    rmvirtualenv 环境名 删除虚拟环境

    创建python3版本虚拟环境
    mkvirtualenv -p python3 环境名

    进入已创建的虚拟环境 workon tab tab 选择 回车

    source activate原生启动虚拟环境

    pip install flask == 版本号 安装响应版本的flask

    查看已安装的包 pip list

    which python 查看python或虚拟环境的所在路径


    from flask import Flask
    static_path 访问静态文件的路径 已弃用
    static_url_path 访问静态文件的路径 指定为none 系统默认为/static
    templates_folder 模板文件的文件夹 默认是 templates
    static_folder 静态文件的问价夹
    host 万能端口=" 0.0.0.0" 只要是本台电脑上的网卡都可以访问改ip


    flask程序
    from flask import Flask # 遵循PEP8的编码格式 使用哪个模块就import指定名称

    app = Flask(__name__#是当前模块的名字,指定模块的绝对路径
    static_url_path="/static"# 静态文件的路径
    static_folder = "static",#指定静态文件夹的名字
    template_folder = "templates"#指定模板文件夹的名字)


    #加载配置
    #1从类对象中加载
    class Config(object):
    DEBUG = True--->类属性必须是大写内置函数规定的小写不满足条件
    app.config.from_object(Config)

    #2从配置文件中加载 config 类似于字典类型
    在静态文件夹中创建一个配置文件 里面写上DEBUG = True
    app.config.from_pyfile("配置文件的路径")

    #3环境变量
    新建环境变量 里面新建配置文件
    app.config.from_envvar("环境变量的名字")

    4app.debug = true

    5app.config["DEBUG"] = True
    获取配置
    app.config.get("DEBUG")

    路由的本质是 url绑定 @app.route()装饰器用于把一个函数绑定到一个url上
    视图函数的返回的响应可以是包含html的简单字符串 也可以是复杂的表单
    同一路由指向多个不同的函数,在匹配过程中,至上而下依次匹配下面的函数并不执行


    # 视图函数和路由
    @app.route("/",methods = ["POST","GET"]) # 路由
    def index(): # 视图函数
    return "hello python"

    浏览器只能获取get请求方式 post需要使用postman插件

    # 动态路由 (带参数的路由)
    @app.route("/user1/<int:user_id>"])# int:转换器

    #自定义转换器 匹配6位数字
    1起转换器的名字regex
    2定义一个类继承自父类
    class RegexConverter(BaseConverter):
    regex = r"[0-9]{6}"
    3把名字作为键 类对象作为值添加到系统默认的转换器字典中
    app.url_map.converters ["regex"]= RegexConverter

    向上查找可以找到父类被调用的地方

    request接收请求报文的数据,进行处理
    request.data.decode() 接收到的数据是二进制 需要解码
    request.form.get("键")-->获取值
    request.args.get("键")--.获取值
    pic_obj = request.files.get("文件名")-->pic_obj.save("新的名字")

    def index(user_id):

    字典数据名 = {}
    # json_data= json.dumps(字典名)--->字典数据转换位json数据--不常用
    # 字典数据 = json.load(json数据)-->json数据转换为字典数据--不常用

    return jsonify(字典数据名)--->将字典数据转换为json数据内容格式也会改变 需要导入jsonify库--最常用
    return redirect(url_for("函数名"))-->通过函数名找到对应函数return"的网址" 需要导入url_for模块
    return user_id
    return '状态码为 666', 666

    if __name__ == '__main__':
    app.run()
    app.run(host="主机ip" port=端口 debug=True-->1重启修改后的代码2抛出异常的位置利于开发)


    子类重写父类的init方法会实例化子类,我自己称之为实例类对象

    获取类中的所有实例对象 使用dir()内置函数

    状态保持 session(服务端) 与 cookie(客户端)

    cookie 是由服务端给客户端的,存储在客户端(通常是加密的),存储cookie的key:value,是纯文本信息 不能存储敏感信息
    不同域名的cookie不能共用
    cookie同源策略 同域名,同路径,如天猫和淘宝cookie共享
    浏览器保存的cookie最大只能由4kb 服务器保存session不限量

    cookie
    设置cookie response.set_cookie("name", "老王")
    cookie 设置过期时间 在设置cookie时设置过期时间 set_cookie(max_age=秒数)
    获取cookie request.cookie.get("cookie的名字")
    删除cookie在退出时删除cookie delete.cookie("name")


    session
    session_id 服务器加密之后以cookie的方式发送给浏览器 ,浏览器无法解析,只有服务器能认识session_id
    设置session session["name"] = "laowang"设置session需要加密 使用app.secret_key = "aaa"#session秘钥
    获取session session.get("name",None)如果没有获取到就返回none
    删除session session.pop("name",None) 删除name对应的键值对,没有name就返回None


    请求钩子 对所有的视图函数进行管理
    @app.before_first_request # 在第一次请求之前会执行 应用场景:链接数据库 因为只需要链接一次
    def before_first_request():

    @app.before_request # 在每一次请求之前都会执行 可以做权限验证工作
    def before_request(): v'c'c'c'c'c'c'c'c'c'c'c'c'c'c'c'c'c'c

    @app.after_request # 在每一次请求之后都会执行 可以做扫尾工作 设置响应报文的内容必须接收一个参数作为响应
    def after_request(respose):
    return response

    @app.terar_down_request # 在每一次请求之后都会执行 会捕获到响应中的异常 可以做捕获异常的操作
    def terar_down_request(e):

    只要访问视图函数都需要走这几步骤 只有第一次链接会触发before_first_request()二次之后就不会

    主动抛出异常 abort()
    http异常的主动抛出 abort()方法
    如果是非法id访问 可以抛出404 -->参数是符合http协议的状态码 404 500 302等
    可以主动拦截非法ip


    捕获异常
    @app.errorhandler(符合http协议的状态码-也可以捕获异常类名)<--如果视图函数出现()里的异常就执行下面的代码
    def exception_handle(e):全局捕获
    return ""


    上下文 在代码执行到某一时刻时,根据之前的代码所做的操作以及下文即将要执行的逻辑,可以决定在当前时刻下可以使用到的变量,或者可以完成的事情

    请求上下文 request context -包含->request(封装了http请求的内容) 和 session(记录请求会话中的用户信息) 保存了c s交互的数据

    应用上下文 application context -->current_app 和 g变量 flask程序运行过程中保存了一些配置信息

    current_app -->获取模块名,获取debug的值 和app的功能是类似的
    g变量 全局临时变量 g对象-->可以动态添加属性 把g放在请求钩子中所有视图函数都能使用
    ---!!只能设置在当前文件中


    flask script -->sys.argv
    app.run 不能通过命令行指定端口,主机ip 以及其它参数 通过flask-script就可以
    使用步骤
    1 pip install flask-script
    2 from flask-script import Manager
    3 manager = Manager(app)
    4 manager.run()
    5 在Edit中添加runserver 参数

    模板----->templates
    jinja2 是由python开发的一个模板引擎
    把变量名给模板替换模板里的内容

    创建一个文件夹templates
    写一个视图函数进行渲染
    指定templates文件夹为templates文件夹
    配置模板语言为jinjia2

    在视图函数中渲染到模板
    return render_template("demo1.html",)多个变量之间使用,隔开


    过滤器的本质就是一个函数 |
    可以链式操作如 {{ my_str | reverse | lower}}
    safe 让带标签的字符串按找格式被浏览器渲染出来

    自定义过滤器
    1.定义一个过滤器的名字
    lireverse
    2.定义一个过滤器函数
    def do_lireverse(li):
    temp = list(li)
    retern list(reversed(temp))
    3.将名字作为键,函数的引用作为值添加到系统默认的过滤器中
    app.add_template_filter(do_lireverse:"lireverse")

    f 函数的引用


    控制代码块{% for my_dict in my_list%}
    {% if loop.index == 1 %}
    <li style="background-color: orange">{{ my_dict.value }}</li>
    {%endfor%}


    模板的继承
    父类模板中需要挖坑{% block contentBlock%}{%endblock%} 用来放子类模板自己的内容

    子类模板中
    {%extens "父类模板名"%}
    {% block contentBlock%}
    {{super()继承父类他自己的内容}}
    子类模板自己的内容
    {%endblock%}

    相同格式的页面抽取父类模板

    1 将两个页面进行对比
    2 去异存同 将不同之处删除 再删除的位置挖坑 {%block 名字Block%}{% endblock %}
    3 起名字可利用标签名或者class的属性进行起名 以便于在继承时进行一一对应
    4 抽取完成的页面就是父类模板
    5 在子类页面中继承父类模板 {% extends "base_news.html" %}
    6 取出父类模板中的坑在里面填上子类模板自己的内容
    {% block scriptBlock %}<script type="text/javascript" src="../static/news/js/detail.js"></script>
    {% endblock %} 相同的内容继承自父类模板


    导入一个模块中的多个类 在被导的模块中使用__all__ = ["类名","类名"]指定要导入的类 使用import * 导入时就是列表中的中

    也可以添加一个字典aa = {} 导入时导字典名


    模板中特有的变量和函数
    config 可以通过模板直接获取
    request
    session
    url_for 通过函数的名字获取函数对应的url


    CSRF 跨站请求伪造

    访问a进行转账 a未退出cookie存在 去访问b b中访问a的转账(cookie存在) a无法判别访问自己的对象

    防止csrf攻击
    确定攻击实在哪个代码块产生
    区分请求是到底是谁(在转账界面设置cookie)
    在webA中的转账界面生成随机数存入cookie中
    将随机的cookie传到界面的form表单的隐藏标签中
    在转账界面对cookie和界面中的cookie进行比较 相等才能进行转账
    由于webB无法获取到webA的隐藏标签,获取它的表单中的cookie值时显示为None 值不等 无法执行转账操作

    实际开发中引入CSRFProected 即可


    flask 数据库 ORM 将表关系对应到类中 sql语句对应到类的方法
    Flask-SQLAlchemy
    创建数据库 create database 数据库名(test) chartset utf8

    pycharm 创建数据库
    点击右侧database -->点击右侧.QL-->创建数据库 create database 数据库名 cahrtset utf8-->刷新-->在下面More中选择添加-->双击使用

    链接数据库 数据库 用户名: 密码 地址 端口 数据库名
    app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:mysql@127.0.0.1:3306/test"

    跟踪动态跟踪修改设置,未设置只会提示警告
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True

    查询时显示原生SQL语句
    app.config['SQLALCHEMY_ECHO'] = True

    实例化数据库sqlalchemy工具对象
    db = SQLALchemy(app)


    创建模型类
    class BookInfo(db.Model): -->继承自实例对象的Model
    __tablename__ = "book-info" # 如果不指明就是类名的小写
    # 表结构
    name = db.Column(db.String(64), unique=True, nullable=Flask)
    pub_date = db.Column(db.String(128), nullable=True)
    is_delete = db.Column(db.Boolean, default=False)
    id = db.Column(db.Integer, primary_key=True)

    # 返回对象的name属性 不写的话返回的是对象的地址引用
    def __repr__(self):
    return self.name


    表操作

    创建表
    db.create_all()

    删除表
    db.drop_all()

    新增一条数据
    创建对象,设置属性
    book1 = BookInfo()
    book1.name = "西游记"
    book1.pub_date = "2001-1-1"

    添加到数据库中
    db.session.add(book1)-----add_all()可以添加多个对象

    真正提交数据
    db.session.commit()

    删除数据
    user = PeopleInfo.query.first() -->查询出一个信息
    db.session.delete(user)-->删除这条数据
    db.session.commit()-->提交删除的操作到数据库
    PeopleInfo.query.all()-->查询全部信息确认是否删除成功


    更新数据
    user = PeopleInfo.query.first() -->查询出一个信息
    user.name = "新的值"-->将对象的属性设为新的值
    db.session.commit()-->将更新的操作提交到数据库
    PeopleInfo.query.first()-->再次查询这条数据确认修改成功

    ----------------------------------------------------->>>>>

    查询 可以使用ipython3进行查询,需要导入
    from 模块名 import *
    类名.query.filter().all()
    filter()返回的是一个查询集
    all()以列表的方式返回查询的所有结果
    类名.query.filter(条件).all()-->模糊查询
    类名.query.filter_by(条件).first()-->精确查询


    多表联合查询
    查询出书下面的所有人物
    方式-
    book = BookInfo.query.filter(BookInfo.name =="三国演义").first()-->查询出book对象
    PeopleInfo.query.filter(PeopleInfo.book_id == book.id).all()-->以列表显示的结果

    方式二
    book = BookInfo.query.filter(BookInfo.name =="三国演义").first()-->查询出book对象
    people = db.relationship("PeopleInfo")-->需要在BookInfo表中添加和PeopleInfo的relationshhip

    book.people


    backref="book"动态的给PeopleInfo添加了一个book属性-->反向引用
    等同于book = db.relationship("BookInfo")-->需要在PeopleInfo表中添加和BookInfo的relationshhip

    lazy ="dynamic"--->book.people是一个查询集占用小内存使用,可以近一步操作
    ------------------------------------------------------>>>>>>>>>

    使用闪现flash()需要设置密钥 它依赖与session

    状态保持
    请求钩子
    csrf
    图书管理案例

    数据库迁移 -->可以记录版本信息 可以反悔操作 必须先备份数据 不删除表就可以修改表结构防止数据丢失
    跟踪设置数据结构 原始数据可以恢复 监听对数据库的操作 必须先备份数据! ! ! ! !

    from flask_migrate import Migrate,MigrateCommand
    from flask_migrate import Manager,Shell

    在flask 中对数据库进行迁移配置
    manager = Manager(app)

    migrate= Manager(app,db)-->关联
    manager.add_command("db", MigrateCommand)


    迁移的命令
    python xx.py db init 创建一个迁移文件夹(迁移文件的仓库)

    python xx.py db migrate -m "注明(修改的内容)"-->生成一个版本文件 将模型添加到迁移文件中 迁移脚本

    python xx.py db upgrade 更新数据库中的表 执行迁移 观察表结构

    返回旧版本
    python xx.py db history 查看历史版本(迁移记录)

    python xx.py db downgrade 版本号 -->返回指定旧版本

    多对多案例分析 如:学生 学科 第三表
    1 创建数据库
    2 数据模型 继承(db.Model)
    表名
    字段= 约束
    关系
    建立连接
    数据模型 继承(db.Model)
    表名
    字段= 约束
    关系
    建立连接
    3 第三表建立关系 直接创建一张表不需要使用模型类
    tb_student_course = db.Table(
    "表名",
    db.Colum("字段名",约束))

    4 添加数据


    蓝图
    为什么使用蓝图--->对程序进行模块化管理--进行协同开发--可以解决循环导入问题--降低耦合度
    模块化管理-->根据一定的条件对函数进行分类(按照功能,按照开发人员等)


    步骤
    1.在蓝图对象模块中导入Blueprint
    2.实例化蓝图对象 = Blueprint("名字",__name__,url_prefix = "/路由的开头 区分模块之间的路由,防止冲突")
    3.定以路由
    4.导入蓝图对象
    5.将蓝图注册到app中(蓝图实例对象)

    一个蓝图模块可以注册多次

    单元测试--->严谨性特别高的程序使用单元测试

    向功能单一的模块进行测试
    断言assert 判断一个函数或方法的一个功能是否符合预期结果
    在单元测试中使用
    在自己写的工具类供别人使用使用需要断言

    例如:
    def func(a,b):
    assert isinstance(a,int),"参数为int类型"
    return a/b
    func(参数,参数)


    单元测试测试接口------------------------------------数据库测试-------晚间实现

    1使用代码模拟浏览器发送一个post请求
    2判断errorcode是否存在字典中
    3判断errorcode是否为-1

    测试代码的步骤
    import unittest
    import app
    import json

    class LoginTest(unittest.TestCase):
    def setUp(self): # 相当于__init__ 做初始化工作
    app.testing = True--->被测试代码有异常会直接抛出
    定义模拟客户端=app.test_clicent()

    def test_empty_username_password(self):
    app.test_clicent().post("url",data={}) #模拟浏览器发送一个post请求
    json_data = responde.data
    dict_data = josn_data.loads()
    print(dict_data)
    self.assertIn("键",容器,"返回的消息")
    self.assertEqual(数据的[键],状态码,"返回的消息")

    def tearDown(): # 类似与__del__()-->析构方法
    数据库的断开操作

    if __name__ == '__main__':
    unittest.run()


    nosql--->以键值对存储数据
    sql------>适用于关系复杂的数据查询场景

    redis-->数据存贮在内存中 速度极快 也支持磁盘存储 重启再次加载使用
    支持 list set zset hash 数据据结构存储 支持主从配置 master--slave

    应用场景
    缓存
    社交类应用
    session共享 购物车

    安装redis
    wget url 下载
    解压
    移动到指定目录
    今日redis目录
    sudo make 进行编译
    sudo make test 测试
    sudo make install 安装命令
    将配置文件.conf加载到etc目录下

    客户端启动 redis-cli
    select 0-15 选择使用的数据库
    服务端启动 redis-serve

    redis 端口 6379

    设置守护进程 demaonize yes

    默认16个数据库 0-15


    redis 哈希 基本的数据类型
    哈希槽 利用哈希算法计算出来的存储数据的空间

    主从 读写分离 数据备份

  • 相关阅读:
    TweenMax参数补充
    jQuery.lazyload详解
    js函数和jquery函数详解
    数数苹果手机中的不科学
    网页全栈工程师要点分析
    瞄了一眼墙外的世界,只能给差评
    脑洞大开的自然语言验证码
    别再迷信 zepto 了
    产品列表页分类筛选、排序的算法实现(PHP)
    大学回顾和C与PHP之路
  • 原文地址:https://www.cnblogs.com/yintaiping/p/10826950.html
Copyright © 2011-2022 走看看