zoukankan      html  css  js  c++  java
  • flask

    image.png

    image.png

    Flask是Python编写的一款轻量级Web应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2。Flask使用 BSD 授权。其中两个环境依赖是Werkzeug和jinja2,这意味着它不需要依赖外部库。正因如此,我们将其称为轻量级框架。

    Flask会话使用签名cookie让用户查看和修改会话内容。它会记录从一个请求到另一个请求的信息。不过,要想修改会话,用户必须有密钥Flask.secret_key。

    基本流程

    from flask import Flask
    image.png
    image.png
    image.png
    image.png

    In [5]: app.url_map
    Out[5]: 
    
    Map([<Rule '/' (HEAD, OPTIONS, GET) -> hello_world>,
     <Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>])
    
    In [4]: app.url_map.converters
    Out[4]: 
    {'any': werkzeug.routing.AnyConverter,
     'default': werkzeug.routing.UnicodeConverter,
     'float': werkzeug.routing.FloatConverter,
     'int': werkzeug.routing.IntegerConverter,
     'path': werkzeug.routing.PathConverter,
     'string': werkzeug.routing.UnicodeConverter,
     'uuid': werkzeug.routing.UUIDConverter}
    

    路由视图函数

    正则匹配路由

    image.png

    int
    @app.route('/<int:age>')
    def age(age):
        return 'here age is %d'%age
    
    float
    @app.route('/<float:hight>')
    def age(hight):
        return 'here hight is %f'%hight
    
    path
    @app.route('/index/<path:name>')
    def str(name):
        return 'welcome %s'%name
    

    image.png

    1 自定义转换器类,继承自BaseConverter
    class MyRegexConverter(BaseConverter):
     2 重写init方法
        def __init__(self,map,regex):
     3 初始化父类空间,子类空间(规则)
    	super(MyRegexConverter, self).__init__(map)    在父类的init中就有map参数,
    	     完成了父类初始化成员变量
    
    	self.regex = regex
    
    4 将自定义的转换器添加到系统默认的转换器列表中,创建一个键值对添加
    app.url_map.converters["re"] = MyRegexConverter
    
    
    #url_map当成第一个参数map传入到init中
    
    #输出系统默认的转换器列表
    print(app.url_map.converters)
    
    #使用自定义的转换器
    #接收三位整数
    
    #使用re(规则),调用init的时候,实际上是传递了两个参数, 
    参数1: app.url_map, 
    参数2: \d{3}规则
    
    @app.route('/<re("\d{3}"):number>')
    def get_three_number(number):
    
        return "the three number is %s"%number
    

    @app.route('/',methods=['POST'])
    def main():
        return '<h1>this is main page</h1>'
    

    视图函数

    image.png

    make_response()函数可以接受1/2/3个参数,跟视图函数的返回值一样, (响应内容,状态码,首部字典)
    并返回一个response对象。

    from flask import make_respoons
    @app.route('/')
    def main():
        se = make_response("hello world")
        se.status = "888"
    
        # se.headers是一个字典
        se.headers["Content-Type"]="application/json"
        return se
    

    image.png

        dict = {
            "name":"laowang",
            "age":13
        }
    se = jsonify(dict)
     return se
    

    image.png

    重定向
    
    @app.route('/demo5')
    defdemo5():
    return redirect('http://www.itheima.com')
    @app.route('/'):
    	return redirect(url_for('index'))
    
    url_for
    from flask import Flask,url_for,redirect
    
    app = Flask(__name__)
    
    @app.route('/jingdong')
    def jingdong():
    
        print(url_for("taobao",token=100)) #得到是taobao视图函数的地址
        return redirect(url_for("taobao",token=100))
    
    
    @app.route('/suning')
    def suning():
    
        print(url_for("taobao",token=200)) #得到是taobao视图函数的地址
        return redirect(url_for("taobao",token=200))
    
    
    @app.route('/taobao/<int:token>')
    def taobao(token):
    
        #判断重定向过来的token值
        if token == 100:
            return "欢迎京东客户,给你打骨折"
        elif token == 200:
            return "欢迎苏宁客户,给你打9折"
        else:
            return "欢迎其他网站客户,给你9.9折"
    
    
    if __name__ == '__main__':
        app.run()
    

    生成连接程序被不同路由的链接时,使用 相对地址足够
    如果要生成在浏览器之外使用的链接,必须使用绝对路径。

    image.png

    from flask import Flask, abort
    
    app = Flask(__name__)
    
    @app.route('/<int:age>')
    def play_game(age):
    
        #判断玩家年龄
        if age > 18:
            return "英雄联盟"
        elif age > 16:
            return "暴力摩托"
        else:
     abort(404)
    
    #捕捉404异常
    @app.errorhandler(404)
    def page_not_found(e):
        print(e)
        return "<h1 style='color:red'>游戏服务器搬家了</h1>"
    
    if __name__ == '__main__':
        app.run(debug=True)
    
    
    自定义错误页面
    @app.errorhandle(404):
        return render_templtate('404.html'),404
    
    @app.errorhandle(500):
        return render_templtate('500.html'),500
    
    如统一处理状态码为500的错误
    @app.errorhandler(500)
    def internal_server_error(e):
      return'服务器搬家了'
    
    
    捕获指定异常
    @app.errorhandler(ZeroDivisionError)
    def zero_division_error(e):
      return'除数不能为0'
    

    request对象

    from flask import request

    请求钩子

    @app.before_first_request
    def xxx():
        在第一次访问时做的准备工作
    
    
    @app.before_request
    def before_request():
        age = request.args.get('age')
        if int(age) >18:
            return 'welcome'
        else:
            return 'age not enough'
    
    对于页面请求发送的拼接数据,进行判断和后续操作,
    一旦在这里有return,后面的@app.route()将不会执行,页面显示在判断中的return值
    
    @app.route('/')
    def hello():
        return 'main page'
    
    
    @app.after_request
    def after_request(rawreturn):
    
        print(rawreturn) >><se 7 bytes [200 OK]>
    
        rawreturn.status='444 not found'
        resp.headers["Content-Type"] = "application/json"
        return rawreturn
    
    @app.teardown_request
    def over(e):
        print(e)
        print('it\'s over time work')
    
    
    在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量  g 
    
    例如:
    before_request 处理程序可以从数据库中加载已登录用户,并将其保存到g.user中
    随后调用视图函数时,视图函数再使用g.uesr获取用户
    
    

    状态保持
    http是一种无状态协议,浏览器请求服务器是无状态的。

    协议对于事务处理没有记忆能力
    对同一个 url 请求没有上下文关系
    每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况
    服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器

    无状态:指一次用户请求时,浏览器、服务器不知道之前这个用户做过什么,每次请求都是一次新的请求。
    无状态原因:浏览器与服务器是使用 socket 套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的 socket 连接,而且服务器也会在处理页面完毕之后销毁页面对象。
    有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等

    实现状态保持的两种方式
    在客户端存储信息使用Cookie
    cookie

    指某些网站为了辨别用户身份、进行会话跟踪而储存在用户本地的数据(通常经过加密)。
    Cookie是由服务器端生成,发送给客户端浏览器,浏览器会将Cookie的key/value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。
    Cookie的key/value可以由服务器端自己定义。
    复数形式Cookies。
    Cookie最早是网景公司的前雇员Lou Montulli在1993年3月的发明。
    应用是判定注册用户是否已经登录网站
    网站的广告推送
    Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用
    Cookie基于域名安全,不同域名的Cookie是不能互相访问的 基于浏览器的同源策略
    当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器,所以在request中可以读取Cookie信息

    image.png

    # 设置cookie
    @app.route('/set_cookie')
    def set_cooke():
        # 获取响应体的对象
        res = make_response('set_cookie')
    
        # 设置cookie
         res.set_cookie('name','cookievalue1')
         res.set_cookie('name1', 'cookievalue2',600)
        return res
    
    # 获取cookie
    @app.route('/get_cookie')
    def get_cookie():
    value1 = request.cookies.get('name')
    value2 = request.cookies['name1']
    
        return 'cookie one is %s,cookie two is %s'%(value1,value2)
    

    在服务器端存储信息使用Session

    session
    对于敏感、重要的信息,建议要存储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息
    在服务器端进行状态保持的方案就是Session
    Session依赖于Cookie
    image.png

    app.config["SECRET_KEY"]='asdasdsad'
    
    # 设置session
    @app.route('/set_session/<name>')
    def set_session(name):
        session['name']=name
        return '设置session'
    
    # 获取session
    @app.route('/get_session')
    def get_session():
    name = session.get('name')
        return 'session name is %s'%name
    

    cookie session本质都是一个个的键值对

    上下文
    相当于一个容器,保存了flask程序运行过程中的一些信息
    image.png

    request 不可能是全局变量, 在多线程服务器中,多个线程同时处理不同客户端发送的不同请求时,每个线程看到的request对象必然是不同,
    Flask 使用上下文让特定的变量在一个线程中全局可访问,与此同时不会干扰其他线程
    
    
    线程是可单独管理的最小指令集,
    进程经常使用多个活动线程,有时还会共享内存或文件句柄等资源
    
     多线程web服务器会会创建一个线程池,在从线程池中选择一个线程用于处理接受到的请求
    app.config.get('DEBUG')
    等同于
    current_app.config.get('DEBUG')
    
    g对象
    @app.before_request
    def before_request():
    g.name = "zhangsan"
    
    @app.route('/')
    def main():
        return g.name
    

    jinja2模板引擎

    Jinja2:是 Python 下一个被广泛应用的模板引擎,是由Python实现的模板语言,他的设计思想来源于 Django 的模板引擎,并扩展了其语法和一系列强大的功能,其是Flask内置的模板语言。
    模板语言:是一种被设计来自动生成文档的简单文本格式,在模板语言中,一般都会把一些变量传给模板,替换模板的特定位置上预先定义好的占位变量名。
    image.png
    image.png
    flask的 render_template 函数吧 Jinja2模板引擎集成到程序中,
    第一个参数模板的文件名,随后的参数都是键值对,表示模板中变量对应的真实值。

        my_list = [
            {
                "id": 1,
                "value": "我爱工作"
            },
    
    return render_template("1e.html",my_list=my_list)
    

    控制结构

    @app.route('/')
    def hello_world():
    
        num = 10
        str = "隔壁老王在练腰"
        tuple = (1,2,3,4)
        list = [5,6,7,8,9]
        dict = {
            "name":"123",
            "age":29
        }
        #携带数据渲染页面
        return render_template("2.html",num=num,str=str,tuple=tuple,list=list,dict=dict)
    

    image.png

    前后端的数据交互  小胡子写法
    在HTML显示后端发过来的数据  格式。
        <h2>获取整数: {{num + 100}}</h2>
        <h2>获取字符串: {{str}}</h2>
        <h2>获取元祖: {{tuple}}, 分开获取:{{ tuple[0] }}, {{ tuple.1 }}</h2>
        <h2>获取列表: {{list}},分开获取:{{ list.0 }}, {{ list.1 }}</h2>
        <h2>获取字典: {{dict}},分开获取:{{ dict.name }},{{ dict["age"] }} </h2>
    

    用 {%%} 定义的控制代码块,可以实现一些语言层次的功能,比如循环或者if语句
    image.png

        <h1>2.取出元祖中所有偶数</h1>
    {% for item in tuple %}
            {% if item %2 == 0 %}
                <h2>{{ item }}</h2>
            {% endif %}
     {% endfor %}
    
    

    loop
    {'age': 123, 'name': 'yy'}
    {% for key in dict %}
        {% if loop.index==2%}  
    		>>loop.index  从1开始迭代,
    选择第二次迭代的值。
            <h1>{{ dict[key] }}</h1>   >>yy
    
        {% elif loop.index0==0 %}
    		>> loop.index0 从0开始迭代,
    选择第一次迭代的值
    
            <h6>{{ dict[key] }}</h6>    >> 123
    
        {% endif %}
    {% endfor %}
    
    
    从1开始迭代
            {% for item in list %}
                {% if loop.index == 1 %}
                    <p>{{ item }}</p>    >>获取第一次迭代获取到的值
                {% elif loop.index == 2 %}
                    <p>{{ item }}</p>    >>获取第两次迭代获取到的值
                {% elif loop.index == 3 %}
                    <p>{{ item }}</p>    >>获取第三次迭代获取到的值
                {% else  %}    
                   <p>{{ item }}</p>    
                {% endif %}
            {% endfor %}
    
    
    
        {% for item in list if item !=9 %}
    	给循环加先前条件,值循环满足条件的列表
                {{ item }}
    
    
        {% endfor %}
    

        <h1>3.遍历字典</h1>
     {% for key in dict %}
    {# dict.key中的key是一个字符串,  dict[key]中的key是个变量 #}
            <h2>{{ key }} = {{ dict[key] }}</h2>
    
       {% endfor %}
    

    循环遍历用的是一层 {} 中间添加%%来控制程序块

    过滤器

    image.png

    safe
    默认情况下,出于安全考虑,
    Jinja2会转义所有变量。
    例如 一个变量的值为 '<h1> hello </h1>'
    jinja2会将其渲染为  '&lt;h1&gt; hello &lt;/&h1&gt;
    浏览器只能显示这个h1元素,但不会进行解释。
    很多情况下需要显示变量中存储的HTML代码,这时就可使用safe过滤器
    别再不可信的值上使用safe过滤器,例如用户再表单中输入的文本
    
    

    image.png
    image.png

    自定义过滤器
    
    ```需求:
    1.求列表中所有偶数和
    2.实现列表反转
    
    from flask import Flask,render_template
    
    app = Flask(__name__)
    
    方法1 
    先定义函数,再将函数添加到过滤器列表中
    def oushu_sum(list):
    
        sum = 0
        for item in list:
            if item %2 == 0:
                sum += item
        return sum
    
    app.add_template_filter(oushu_sum,"OUSHU_SUM")
    
    方法2
    定义函数的时候, 就使用过滤器装饰
    @app.template_filter("my_reverse")
    def reverse_function(list):
    list.reverse()
        return list
    
    @app.route('/')
    def hello_world():
    
        return render_template("file04custom_filter.html")
    
    if __name__ == '__main__':
        app.run(debug=True)
    
    
    
    HTML文件
        <h2>原列表: {{ [1,2,3,4,5,6,7] }}</h2>
        <h2>原列表偶数和: {{ [1,2,3,4,5,6,7] | OUSHU_SUM}}</h2>
        <h2>原列表反转: {{ [1,2,3,4,5,6,7] | my_reverse}}</h2>
    
        {# 使用系统提供的过滤器和自定义过滤器实现降序输出 #}
        <h3> 升序: {{ [5,8,1,3,9] | sort}} </h3>
        <h3> 降序: {{ [5,8,1,3,9] | sort | my_reverse}} </h3>
    

    模板代码复用

    image.png

        {% macro inputmode(name,password) %}
            <p>username: <input type="text" name="username" value="{{ name }}"></p>
            <p>password: <input type="password" name="password" value="{{ password }}"></p>
            <p><input type="submit" value="提交按钮"></p>
        {% endmacro %}
    
    
    其他文件使用宏
      其他文件other_macro.html
    {% macro input(name,password) %}
    <label>{{ name }}:</label><input type="text" name="username"><br>
    <label>{{ password }}:</label><input type="password" name="username"><br>
    {% endmacro %}
    
    
    
    
    从other_macro.html引入宏
        {% import 'other_macro.html' as other_macro %}
        {{ other_macro.input2('用户名',"密码") }}
        {{ other_macro.input3() }}
    

        {% block contentmodel %}
        <h1>静夜思</h1>
        <h2>床前我明月光</h2>
        <h2>疑似他地上霜</h2>
        <h2>举头那望明月</h2>
        <h2>低头他思故乡</h2>
    
        <h3>作者: 李白</h3>
        {% endblock %}
    
    
    super
    {% block contentmodel %}
        {{ super()}}
        <h1>这是重写的父类模板</h1>
    {% endblock %}
    

    image.png
    image.png

    模板特有的变量和函数

    image.png

    
    @app.route('/index2/<int:num>')
    def index2(num):
        return num
    

    flask-moment 本地化日期和时间
    image.png

    CSRF

    image.png
    image.png
    csrf_token阻止CSRF攻击
    实现csrf 保护, flask-WTF需要程序设置一个秘钥,
    flask-WTF使用这个秘钥生成加密令牌,再用领跑验证请求中表单数据的真伪,
    image.png

    流程



    ajax 给表单设置一个事件   
    监听submit
    

    数据库操作

    orm

    图示



    流程

    CURD

    通过数据库管理对数据库所做的改动,
    在flask-SQLAlchemy中,会话由 db.session表示
    准备把对象写入数据库之前,先要将其添加到会话中
    这里的session 和 上下文中的session没有关系,
    数据库会话也称作为事务
    数据库会话能保证数据库的一致性。
    提交操作使用原子方式把会话中的对象全部写入数据库。
    如果在写入回话的过程中发生了错误,整个会话都会失效。
    如果始终把相关改动放在会话中提交,就能避免因为部分更新导致的数据库不一致性,
    在准备把数据写入数据库前,先将数据添加到会话中然后调用 db.session.commit() 方法提交会话。

    通过 query 对象操作数据。

    最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据库查询
    
    当  模型.query 的时候,就已经把所有数据都给取出来了,
    再通过过滤器,执行,得出想要的数据。
    
    过滤器
    
    filter()
    把过滤器添加到原查询上,返回一个新查询
    filter_by()
    把等值过滤器添加到原查询上,返回一个新查询
    limit
    使用指定的值限定原查询返回的结果
    offset()
    偏移原查询返回的结果,返回一个新查询
    order_by()
    根据指定条件对原查询结果进行排序,返回一个新查询
    group_by()
    根据指定条件对原查询结果进行分组,返回一个新查询
    
    
    执行器
    
    all()
    以列表形式返回查询的所有结果
    first()
    返回查询的第一个结果,如果未查到,返回None
    first_or_404()
    返回查询的第一个结果,如果未查到,终止请求、返回404错误响应
    get()
    返回指定主键对应的行,如不存在,返回None
    get_or_404()
    返回指定主键对应的行,如不存在,返回404
    count()
    返回查询结果的数量
    paginate()
    返回一个Paginate对象,它包含指定范围内的结果
    


    查询数据后删除
    user = User.query.first()
    db.session.delete(user)
    db.session.commit()
    User.query.all()
    
    更新数据
    user = User.query.first()
    user.name = 'dong'
    db.session.commit()
    User.query.first()
    

    str
    srt(User.query.filter_by(role = user_role))
    
    SELECT users.id AS users_id, users_id,users.username AS users_username,
    users.role_id AS users_role_id FROM users WHERE : param_1 = users.role_id
    

    Role
    class Role(db.Model):
        __tablename__ = "roles"
        id = db.Column(db.Integer,primary_key=True)
        name = db.Column(db.String(16),unique=True)
    
    users = db.relationship("User",backref="role")
    
        def __repr__(self):
            return "<Role:%s>"%self.name
    
    
    User
    class User(db.Model):
        __tablename__ = "users"
        id = db.Column(db.Integer,primary_key=True)
        name = db.Column(db.String(16),unique=True)
    
     role_id = db.Column(db.Integer,db.ForeignKey(Role.id))
    
    执行 role.users表达式的时候,隐含的查询会调用 all()返回一个用户列表
    query对象是隐藏的,因此无法指定更精确的查询过滤器。
    
    

    是通过过滤器和执行器的搭配来实现,过滤器可以没有,但一定要执行

    表关系

    image.png

    数据库迁移

    追踪数据库模式的变化,然后把变动应用到数据库中
    为了备份表结构

    迁移流程

    使用命令进行迁移操作


    from flask.ext.script import Shell
    
    def make_shell_context():
       return dict(app=app,db=db.User=User,Role=Role)
    manager.add_command('shell',Shell(make_context = make_shell_context))
    
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from flask_script import Manager
    from flask_migrate import  Migrate,MigrateCommand
    
    app = Flask(__name__)
    
    #2 设置数据库配置信息,关联app对象
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:mysql@localhost:3306/day04'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    db = SQLAlchemy(app)
    
    
    #3使用migrate关联app和db
    Migrate(app,db)
    
    #4使用manager 管理app
    manager = Manager(app)
    
    #5使用migratecommand 给manager添加操作命令
    manager.add_command('db',MigrateCommand)
    
    #6 创建模型类
    class Student(db.Model):
        __tablename__ = 'student1'
        id = db.Column(db.Integer,primary_key=1)
        name = db.Column(db.String(16))
    
    @app.route('/')
    def hello():
        return 'hello'
    
    if __name__ == '__main__':
     manager.run()
    

    蓝图 Blueprint

    方法1:先在其他文件中定义好方法,再到启动入口装饰视图函数,缺点:耦合性太强,一个地方改动,其他也得动,所以引入了蓝图
    方法2: flask中提供的类,不需要安装就可以使用

    使用蓝图对象装饰视图函数
    文件1
    
    #1 导入蓝图类
    from flask import Blueprint
    
    #2 创建蓝图对象
    product_blue = Blueprint('blue',__name__)
    blue:  该蓝图对象装饰的视图函数到时候都在blue地下,
    
    #3 使用蓝图装饰视图函数
    @product_blue.route('/')
    def hello():
        return 'hello'
    
    @product_blue.route('/index')
    def index():
        return 'index'
    
    将蓝图注册到app对象中
    app.register_blueprint(blue_product)
    

    含有__init__文件。单一的py文件称为模块

    #1 导入类
    from flask import Blueprint
    
    #2 创建蓝图对象
    blue_product = Blueprint('blue',__name__)
    
    #4 引入试图函数
    from day4.user import view
    (此时不存在循环导入蓝图对象的问题,Python是弱类型语言,只要在内存中存在之后,就不再引入
    )
    
    views.py
    from day4.user import blue_product
    引入蓝图对象来装饰
    
    #3 用蓝图装饰视图函数
    @blue_product.route('/')
    def hello():
        return 'hello'
    
    @blue_product.route('/')
    def index():
        return 'index'
    
    @blue_product.route('/')
    def error():
        return 'error'
    
    
    入口文件
    from flask import Flask
    from day4.user import blue_product
    引入蓝图对象
    
    app = Flask(__name__)
    
    #5 将蓝图对象注册到app中
    app.register_blueprint(blue_product)
    
    if __name__ == '__main__':
        print(app.url_map)
        app.run(debug=True)
    
    
    app.url_map >>
    Map([<Rule '/' (HEAD, GET, OPTIONS) -> blue.hello>,
     <Rule '/' (HEAD, GET, OPTIONS) -> blue.index>,
     <Rule '/' (HEAD, GET, OPTIONS) -> blue.error>,
     <Rule '/static/<filename>'
     (HEAD, GET, OPTIONS) -> static>])
    
    

    from unittest import TestCase
    
    #1 自定义类,继承TestCase
    class Mytest(TestCase):
    
        #2 两个固定方法 setup teardown
        def setUp(self):
            print('setup')
        def tearDown(self):
            print('teardown')
    
        #3 编写测试方法
        def test_data(self):
            print('testtest')
    
            self.assert...(boolean,msg)
    	断言
    直接右键执行,开始测试
    
    编写测试方法
    def test_app(self):
        self.assert....()
    
    
    常见的断言方法
    assertEqual     如果两个值相等,则pass
    assertNotEqual  如果两个值不相等,则pass
    assertTrue      判断bool值为True,则pass
    assertFalse     判断bool值为False,则pass
    assertIsNone    不存在,则pass
    assertIsNotNone 存在,则pass
    
    #coding=utf-8
    import unittest
    from author_book import *
    
    #自定义测试类,setUp方法和tearDown方法会分别在测试前后执行。以test_开头的函数就是具体的测试代码。
    classDatabaseTestCase(unittest.TestCase):
    defsetUp(self):
            app.config['TESTING'] = True
            app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@localhost/test0'
            self.app = app
            db.create_all()
    
    deftearDown(self):
            db.session.remove()
            db.drop_all()
    
    #测试代码
    deftest_append_data(self):
            au = Author(name='itcast')
            bk = Book(info='python')
            db.session.add_all([au,bk])
            db.session.commit()
            author = Author.query.filter_by(name='itcast').first()
            book = Book.query.filter_by(info='python').first()
    #断言数据存在
            self.assertIsNotNone(author)
            self.assertIsNotNone(book)
    
  • 相关阅读:
    垂直margin为什么会重叠
    forEach()和for/in循环的缺点与for-of循环
    使用CleanWebpackPlugin插件报错原因:CleanWebpackPlugin is not a constructor
    Vue中常用的组件库
    Vue中使用keep-alive优化网页性能
    Vue中router路由异步加载组件-优化性能
    面试题-JS中的作用域相关问题
    JS中的垃圾回收机制
    【转】 SpringMVC详解(三)------基于注解的入门实例
    【转】 SpringMVC详解(二)------详细架构
  • 原文地址:https://www.cnblogs.com/cizao/p/11481938.html
Copyright © 2011-2022 走看看