flask基础入门

1.name

1)作为启动文件:__name__=__main__
2)作为导入模块:__name__=模块名

2.flask启动参数

1)import_name:项目根目录,默认__name__
2)static_url_path:访问静态资源的url前缀,默认是static
3)static_folder:静态资源目录,默认是__name__/static/
4)template_folder:模版文件目录,默认是__name__/template/

3.参数的配置有四种方式

1)app.config.from_pyfile("config.cfg")
2)app.config.from_object(Config)
3)app.config.envvar(variable_name)
4)app.config["DEBUG"] = True

4.current_app

全局代理app

5.app.url_map

查看路径映射

6.redirect和url_for

1)redirect:重定向
2)url_for:根据视图函数名找到路径

7.路径中提取参数(转换器)

1)flask默认实现转换器规则:int,float,path
2)<int: order_id>
3)自己定义万能转换器
    (1)定义转换器类
    (2)将自定义转换器类添加到flask中
    (3)传参调用转换器
from flask import Flask
from werkzeug.routing import BaseConverter

app = Flask(__name__)

class RegexConverter(BaseConverter):
    """万能转换器"""
    def __init__(self, url_map, regex):
        super(RegexConverter, self).__init__(url_map)
        self.regex = regex
        
    def to_python(self, value):
        """对参数值进行处理,value是在路径进行表达式匹配之后的提取的参数"""
        return value
        
    def to_url(self, value):
        """适用url_for的时候调用,用于修改url_for中的参数"""
        return value
        

app.url_map.converters['re'] = RegexConverter


@app.route("/index/<re(r'1[345678]\d{9}'):mobile>")
def index(mobile):
    return 'this is my mobiel: %s', mobile

8.request

1)form:表单格式的数据存在form字段中,form是一个类字典(ps:有request.form.getlist('name')方法)
2)data:接收非表单的json数据等
3)args:从查询字符串中获取参数(url问号后的数据)
4)cookies:返回请求中的cookie信息,dict类型
5)headers:返回请求头信息,dict类型
6)method:获取前端请求类型,返回结果为大写字符串,方便根据请求方式进行不同处理
7)url:获取用户请求路径,string类型
8)files:获取用户上传的文件,返回文件对象。

9.abort

1)可以终止视图函数执行
2)返回给前段特定信息
3)可以接收标准的http代码
4)也可以接收flask中的Response对象

10.自定义错误处理方法

from flask import Flask, abort

app = Flask(__name__)


@app.errorhandler(404)
def handle_404_error(err):
    return '404 err ' + str(err)


@app.route("/")
def index2():
    abort(404)
    return 'this is index page'


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

11.普通自定义响应信息

from flask import Flask

app = Flask(__name__)


@app.route("/")
def index():
    #       响应体                状态码(可以为字符串)  响应头
    # return 'this is index page', 200, [('City', 'Beijing'), ('Name', 'Zhangsan')]
    return 'this is index page', 200, {'City': 'Beijing', 'Name': 'Zhangsan'}


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

12.适用make_response构造响应信息

from flask import Flask, make_response

app = Flask(__name__)


@app.route("/")
def index():
    resp = make_response('this is index page')
    resp.status = '300'
    resp.headers['City'] = 'Beijing'
    return resp


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

13.利用jsonify返回json数据

from flask import Flask, jsonify

app = Flask(__name__)


@app.route("/")
def index():
    data = {
        'name': 'zhangsan',
        'city': 'beijing'
    }
    return jsonify(data)


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

14.cookie

from flask import Flask, make_response, request

app = Flask(__name__)


@app.route("/set_cookie")
def set_cookie():
    resp = make_response('success')
    resp.set_cookie('name', 'zhangsan')
    resp.set_cookie('age', '12')
    # 设置过期时间(秒)
    resp.set_cookie('city', 'beijing', max_age=3600)
    # 可以采用headers设置cookie
    # resp.headers['Set-Cookie'] = "sex=man"
    return resp


@app.route('/get_cookie')
def get_cookie():
    cook = request.cookies.get('name')
    return cook


@app.route('/del_cookie')
def del_cookie():
    resp = make_response('del cookie success')
    # 并不是删除,而是设置请求的过期时间
    resp.delete_cookie('age')
    return resp


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

15.session

flask把session数据通过加密保存到前端的cookie中
from flask import Flask, session

app = Flask(__name__)
app.config['SECRET_KEY'] = 'asdfadfc'


@app.route("/login")
def login():
    session['name'] = 'zhangsan'
    return 'login success'


@app.route('/index')
def index():
    name = session.get('name')
    return 'hello' + name


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

16.勾子

1)before_first_request:在处理第一个请求前运行
2)before_request:在每次请求前运行
3)after_request:如果被调用的视图函数没有未处理的异常抛出,在每次请求后运行
4)teardown_request:在每次被调用的视图函数请求后运行,即使有未处理的异常抛出(debug模式不起作用)
from flask import Flask

app = Flask(__name__)


@app.route('/index')
def index():
    print 'index'
    # raise Exception('123')
    return 'index page'


@app.before_first_request
def handle_before_first_request():
    print 'handle_before_first_request'


@app.before_request
def handle_before_request():
    print 'handle_before_request'


@app.after_request
def handle_after_request(response):
    print 'handle_after_request'
    return response


@app.teardown_request
def handle_teardown_request(response):
    print 'handle_teardown_request'
    return response


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

17.上下文(线程局部变量实现)

# 实现方式
requser = {
    '线程A': {
        'form': {},
        'args': 1,
    },
    '线程B': {
        'form': {},
        'args': 2,
    }
}
1)request
2)session

18.应用上下文

1)current_app:表示当前运行程序文件的程序实例,读取app配置信息
2)g:一次请求多个函数之间传参用,每次请求都会重设这个变量

19.flask_script

from flask import Flask
from flask_script import Manager


app = Flask(__name__)
manage = Manager(app)


@app.route('/index')
def index():
    return 'index page'


if __name__ == '__main__':
    manage.run()
1)启动:python app.py runserver
2)启动加参数:python app.py runserver --help
             python app.py runserver -h 0.0.0.0 -p 8000
3)交互方式:预先导入app中的变量
             python app.py shell

20.jinja2变量

from flask import Flask, render_template


app = Flask(__name__, template_folder='../template')


@app.route('/index')
def index():
    # return render_template('index.html', name='zhangsan', age=18)
    data = {
        'name': 'zhangsan',
        'age': 18,
        'my_dict': {'city': 'beijing'},
        'my_list': [1, 2, 3, 4],
        'my_ind': 2
    }
    return render_template('index.html', **data)


if __name__ == '__main__':
    app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>name: {{ name }}</p>
    <p>age: {{ age }}</p>
    <p>my_dict: city = {{ my_dict["city"] }}</p>
    <p>my_list: {{ my_list }}</p>
    <p>my_list[my_ind]: {{ my_list[my_ind] }}</p>
    <p>my_list[0] + my_list[1]: {{ my_list[0] + my_list[1] }}</p>
</body>
</html>

21.jinja2过滤器 |

使用方法:<p>{{ '  hello world  ' | trim | upper }}</p>
1)safe:禁用转义(xss攻击:前端注入js脚本)
from flask import Flask, render_template, request


app = Flask(__name__, template_folder='../template')


@app.route('/index', methods=['GET', 'POST'])
def index():
    text = ''
    if request.method == 'POST':
        text = request.form.get('text')
    return render_template('index.html', text=text)


if __name__ == '__main__':
    app.run(debug=True)

# 攻击代码:<script>alert("hello attack");</script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form method="post">
        <textarea name="text"></textarea>
        <input type="submit" value="提交">
    </form>
    {{ text | safe }}
</body>
</html>
2)capitalize:把变量值的首字母大写,其余字母小写
3)lower:把值转为小写
4)upper:把值转为大写
5)title:把值中的每个单词的首字母都转成大写
6)trim:把值的首尾空格去掉
7)reserse:字符串反转
8)format:格式化输出  <p>{{ '%s is %s' | format('age', 18) }}</p>
9)striptags:渲染前把值中所有标签都去掉  <p>{{ '<em>is</em>' | striptags }}</p>
10)first:取第一个元素  <p>{{ [1,2,3] | first }}</p>
11)last:取最后一个元素
12)length:获取列表长度
13)sum:列表求和
14)sort:列表排序

22.jinja2自定义过滤器

from flask import Flask, render_template, request


app = Flask(__name__, template_folder='../template')

@app.template_filter('list_max')
def my_filter(data):
    """实现对获取数组中最大数的过滤器"""
    return max(data)

# 注册过滤器方案2
# app.add_template_filter(my_filter, 'list_max')

23.flask-wtf表单扩展

from flask import Flask, render_template, redirect, url_for, session
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, EqualTo

app = Flask(__name__, template_folder='../template')
app.config['SECRET_KEY'] = 'asdf'


class RegisterForm(FlaskForm):
    """自定义注册表单模型类"""
    user_name = StringField(label=u'用户名', validators=[DataRequired(u'用户名不能为空')])
    password = PasswordField(label=u'密码', validators=[DataRequired(u'密码不能为空')])
    password2 = PasswordField(label=u'确认密码', validators=[DataRequired(u'确认密码不能为空'),
                                                         EqualTo('password', u'两次密码不一致')])
    submit = SubmitField(label=u'提交')


@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegisterForm()
    # 校验form中的所有数据符合定义
    if form.validate_on_submit():
        # 验证符合后的逻辑
        user_name = form.user_name.data
        password = form.password.data
        session['user_name'] = user_name
        session['password'] = password
        return redirect(url_for('index'))

    return render_template('register.html', form=form)


@app.route('/index')
def index():
    user_name = session.get('user_name', 'zhangsan')
    return 'hello ' + user_name


if __name__ == '__main__':
    app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
</head>
<body>
    <form method="post">
        <!--防止csrf攻击-->
        {{ form.csrf_token }}

        {{ form.user_name.label }}
        <p>{{ form.user_name }}</p>
        {% for msg in form.user_name.errors %}
        <p>{{ msg }}</p>
        {% endfor %}

        {{ form.password.label }}
        <p>{{ form.password }}</p>
        {% for msg in form.password.errors %}
        <p>{{ msg }}</p>
        {% endfor %}

        {{ form.password2.label }}
        <p>{{ form.password2 }}</p>
        {% for msg in form.password2.errors %}
        <p>{{ msg }}</p>
        {% endfor %}

        {{ form.submit }}
    </form>
</body>
</html>

24.jinja2宏

1)基本使用
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
</head>
<body>
    {% macro input(type, value, size=30) %}
    <input type="{{type}}" value="{{value}}" size="{{size}}">
    {% endmacro %}

    <h1>第一次调用input</h1>
    {{ input('text', '', 50) }}

    <h1>第二次调用input</h1>
    {{ input('password', '', 100) }}
</body>
</html>
2)从模块引用,先将宏定义放到macro_input.html中,然后执行以下命令
{% import "macro_input.html" as m_input %}
{{ m_input.input('password', '', 100) }}
3)模版继承

25.orm-flask-sqlalchemy

from flask import Flask
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__, template_folder='../template')
# 数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:2022@127.0.0.1:3306/test'
# 设置sqlalcheny自动跟踪数据变化,同步修改模型类
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# 显示模型类最终的sql语句,测试时用
# app.config['SQLALCHEMY_ECHO'] = True

db = SQLAlchemy(app)


class User(db.Model):
    __tablename__ = 'tbl_users'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    email = db.Column(db.String(128), unique=True)
    password = db.Column(db.String(128))
    role_id = db.Column(db.Integer, db.ForeignKey("tbl_roles.id"))


class Role(db.Model):
    __tablename__ = 'tbl_roles'
    
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True)
    users = db.relationship("User", backref="role")


if __name__ == '__main__':
    db.drop_all()
    db.create_all()

    # 增
    role1 = Role(name='admin')
    db.session.add(role1)

    role2 = Role(name='stuff')
    db.session.add(role2)

    db.session.commit()

    us1 = User(name='zhang', email='zhang@163.com', password='123456', role_id=role1.id)
    us2 = User(name='wang', email='wang@163.com', password='234567', role_id=role2.id)
    us3 = User(name='li', email='li@182.com', password='345678', role_id=role2.id)
    us4 = User(name='sun', email='sun@132.com', password='456789', role_id=role2.id)

    db.session.add_all([us1, us2, us3, us4])
    db.session.commit()

    # 查
    li = Role.query.all()
    for i in li:
        print i.id, i.name

    print Role.query.first().name
    print Role.query.get(2).name

    # 通过session查询
    li1 = db.session.query(Role).all()
    for i in li1:
        print i.name
    print db.session.query(Role).first().name

    # 过滤查询
    li2 = User.query.filter_by(name='zhang').all()
    for i in li2:
        print i.name
    # 查询无结果返回None
    print User.query.filter_by(name='zhang', role_id=1).first().email
    # session形式
    print db.session.query(User).filter_by(name='zhang', role_id=1).first().name

    # filter查询and
    print User.query.filter(User.name=='zhang', User.role_id==1).first().email

    # filter查询or
    from sqlalchemy import or_
    li3 = User.query.filter(or_(User.name=='zhang', User.email.endswith('163.com'))).all()
    for i in li3:
        print i.name, i.email

    # offset跳过前边n条
    li4 = User.query.offset(2)
    for i in li4:
        print i.name

    # limit限制返回条数
    li5 = User.query.offset(1).limit(2)
    for i in li5:
        print i.name

    # 排序查询
    li6 = User.query.order_by(User.id.desc())
    for i in li6:
        print i.id, i.name

    # group_by+聚合函数查询
    print db.session.query(User.role_id).group_by(User.role_id).all()
    from sqlalchemy import func
    print db.session.query(User.role_id, func.count(User.role_id)).group_by(User.role_id).all()

    # 关联查询relationship
    li7 = Role.query.get(2)
    for i in li7.users:
        print i.name

    # 反向查询backref
    user = User.query.get(2)
    print user.role.name

    # 修改更新操作
    us4 = User.query.get(4)
    us4.name = 'hou'
    us4.email = 'hou@132.com'
    db.session.commit()

    # update
    User.query.filter_by(name='wang').update({'name': 'hou', 'email': 'hou@163.com'})
    db.session.commit()

    # 删除
    user = User.query.get(2)
    db.session.delete(user)
    db.session.commit()

    User.query.filter_by(name='wang').delete()
    db.session.commit()

26.完整使用案例

from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired


app = Flask(__name__, template_folder='../template', static_folder='../static')


# 数据库配置
class Config(object):
    SQLALCHEMY_DATABASE_URI = "mysql://root:2022@127.0.0.1:3306/test"
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    SECRET_KEY = 'asdfasd'


app.config.from_object(Config)
db = SQLAlchemy(app)


# 模型类
class Auth(db.Model):
    __tablename__ = 'tbl_auths'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    book_id = db.relationship("Book", backref="auth")


class Book(db.Model):
    __tablename__ = 'tbl_books'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    auth_id = db.Column(db.Integer, db.ForeignKey("tbl_auths.id"))


# 表单模型类
class AuthBookForm(FlaskForm):
    auth_name = StringField(label=u'作者', validators=[DataRequired(u'作者必填')])
    book_name = StringField(label=u'书籍', validators=[DataRequired(u'书籍必填')])
    submit = SubmitField(u'保存')


# 视图
@app.route("/", methods=['GET', 'POST'])
def index():
    form = AuthBookForm()
    if form.validate_on_submit():
        auths = Auth.query.all()
        auth_name = form.auth_name.data
        book_name = form.book_name.data
        if auth_name not in [i.name for i in auths]:
            au = Auth(name=auth_name)
            db.session.add_all([au])
            db.session.commit()
        else:
            for i in auths:
                if auth_name == i.name:
                    au = Auth(name=auth_name, id=i.id)

        bo = Book(name=book_name, auth_id=au.id)
        db.session.add_all([bo])
        db.session.commit()

    auths = Auth.query.all()
    return render_template('index.html', authors=auths, form=form)


# 删除接口
@app.route('/delete', methods=['GET'])
def delete():
    book_id = request.args.get('book_id')
    book = Book.query.get(book_id)
    db.session.delete(book)
    db.session.commit()
    return redirect(url_for('index'))

if __name__ == '__main__':
    # db.drop_all()
    # db.create_all()

    # au1 = Auth(name=u'aaa')
    # au2 = Auth(name=u'sss')
    # au3 = Auth(name=u'ddd')
    # au4 = Auth(name=u'fff')
    #
    # db.session.add_all([au1, au2, au3, au4])
    # db.session.commit()
    #
    # bo1 = Book(name=u'zzz', auth_id=au1.id)
    # bo2 = Book(name=u'xxx', auth_id=au2.id)
    # bo3 = Book(name=u'ccc', auth_id=au2.id)
    # bo4 = Book(name=u'vvv', auth_id=au3.id)
    # bo5 = Book(name=u'bbb', auth_id=au4.id)
    #
    # db.session.add_all([bo1, bo2, bo3, bo4, bo5])
    # db.session.commit()
    app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form method="post">
        {{ form.csrf_token }}

        {{ form.auth_name.label }}
        <p>{{ form.auth_name }}</p>
        {% for msg in form.auth_name.errors %}
            <p>{{ msg }}</p>
        {% endfor %}

        {{ form.book_name.label }}
        <p>{{ form.book_name }}</p>
        {% for msg in form.book_name.errors %}
            <p>{{ msg }}</p>
        {% endfor %}

        {{ form.submit }}
    </form>
    <hr/>
    <ul>
        {% for auth in authors %}
        <li>作者:{{ auth.name }}</li>
            <ul>
                {% for book in auth.book_id %}
                <li>书籍:{{ book.name }}</li>
                <a href="/delete?book_id={{ book.id }}">删除</a>
                {% endfor %}
            </ul>
        {% endfor %}
    </ul>
</body>
</html>

27.flask-migrate扩展

相当于同步模型类的更改到mysql,采用脚本形式
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand


app = Flask(__name__, template_folder='../template', static_folder='../static')


# 数据库配置
class Config(object):
    SQLALCHEMY_DATABASE_URI = "mysql://root:2022@127.0.0.1:3306/test"
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    SECRET_KEY = 'asdfasd'


app.config.from_object(Config)
db = SQLAlchemy(app)

manager = Manager(app)
Migrate(app, db)
manager.add_command('db', MigrateCommand)


# 模型类
class Auth(db.Model):
    __tablename__ = 'tbl_auths'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    email = db.Column(db.String(128), unique=True)


if __name__ == '__main__':
    manager.run()
1)第一次初始化:python app.py db init
2)相当于git的commit:python app.py db migrate -m 'add emaile'
3)相当于git的push:python app.py db upgrade

28.循环导入问题

1)延迟导入
2)装饰器
# app文件
from flask import Flask
from user import user


app = Flask(__name__)
app.route('/user')(user)


@app.route('/index')
def index():
    return 'index page'


if __name__ == '__main__':
    app.run()
# user文件
def user():
    return 'user page'
3)蓝图
# app文件
from flask import Flask
from user import user
from goods import goods


app = Flask(__name__)

app.register_blueprint(user, url_prefix='/user')
app.register_blueprint(goods, url_prefix='/goods')


@app.route('/index')
def index():
    return 'index page'


if __name__ == '__main__':
    app.run()
# user文件
from flask import Blueprint


user = Blueprint('user', __name__)


@user.route('/register')
def register():
    return 'register page'
# goods文件
from flask import Blueprint


goods = Blueprint('goods', __name__)


@goods.route('/get_goods')
def get_goods():
    return 'get goods page'

29.蓝图小模块拆分形式

1)目录结构
    pro
    ----goods
    --------template
    ------------goods.html
    --------__init__.py
    --------view.py
    ----app.py
2)代码
#app.py
from flask import Flask
from goods import app_good


app = Flask(__name__)

app.register_blueprint(app_good, url_prefix='/get_goods')


@app.route('/index')
def index():
    return 'index page'


if __name__ == '__main__':
    app.run(debug=True)

# __init__py
from flask import Blueprint

app_good = Blueprint('app_good', __name__, template_folder='template')

from .view import get_goods
# view.py
from flask import render_template
from . import app_good


@app_good.route('/get_goods')
def get_goods():
    return render_template('goods.html')
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1> goods </h1>
</body>
</html>

30.单元测试-接口

from flask import Flask, request, jsonify


app = Flask(__name__)


@app.route('/login', methods=["POST"])
def login():
    name = request.form.get('name')
    password = request.form.get('password')

    if not all([name, password]):
        resp = {
            'code': 1,
            'message': 'invalid params'
        }
        return jsonify(resp)

    if name == 'admin' and password == 'python':
        resp = {
            'code': 0,
            'message': 'login success'
        }
        return jsonify(resp)
    else:
        resp = {
            'code': 2,
            'message': 'wrong name or password'
        }
        return jsonify(resp)


if __name__ == '__main__':
    app.run(debug=True)
import unittest
from app import app
import json


class LoginTest(unittest.TestCase):
    """单元测试"""

    def setUp(self):
        """相当于__init__函数"""
        self.client = app.test_client()
        # 打开测试模式,方便查看服务端错误原因
        app.testing = True

    def test_empty_user_name_password(self):
        """测试用户名和密码不完整情况,函数开头必须是test_形式"""
        # 都不传
        ret = self.client.post('/login', data={})
        resp = json.loads(ret.data)
        # 断言测试
        self.assertIn("code", resp)
        self.assertEqual(1, resp['code'])

        # 只传一个
        ret = self.client.post('/login', data={'name': 'admin'})
        resp = json.loads(ret.data)
        # 断言测试
        self.assertIn("code", resp)
        self.assertEqual(1, resp['code'])

    def test_login_success(self):
        """测试登陆成功情况,函数开头必须是test_形式"""
        ret = self.client.post('/login', data={'name': 'admin', 'password': 'python'})
        resp = json.loads(ret.data)
        # 断言测试
        self.assertIn("code", resp)
        self.assertEqual(0, resp['code'])

    def test_wrong_name_password(self):
        """测试用户名和密码错误情况,函数开头必须是test_形式"""
        ret = self.client.post('/login', data={'name': 'root', 'password': '123'})
        resp = json.loads(ret.data)
        # 断言测试
        self.assertIn("code", resp)
        self.assertEqual(2, resp['code'])


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

31.单元测试-数据库

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__, template_folder='../template')
# 数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:2022@127.0.0.1:3306/test'
# 设置sqlalcheny自动跟踪数据变化,同步修改模型类
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# 显示模型类最终的sql语句,测试时用
# app.config['SQLALCHEMY_ECHO'] = True

db = SQLAlchemy(app)


class User(db.Model):
    __tablename__ = 'tbl_users'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    email = db.Column(db.String(128), unique=True)
    password = db.Column(db.String(128))
import unittest
from app import app, User, db


class DatabaseTest(unittest.TestCase):
    """单元测试"""

    def setUp(self):
        """相当于__init__函数"""
        # 打开测试模式,方便查看服务端错误原因
        app.testing = True
        app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:2022@127.0.0.1:3306/flask_test'
        db.create_all()

    def test_add_user(self):
        """测试增加用户,函数开头必须是test_形式"""
        user = User(name='zhangsan', email='131111@163.com', password='123345')
        db.session.add(user)
        db.session.commit()

        result = User.query.filter_by(name='zhangsan').first()
        self.assertIsNotNone(result)

    def tearDown(self):
        """测试都执行完后清理操作"""
        db.session.remove()
        db.drop_all()


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

32.部署

nginx+gunicron+flask
1)nginx配置

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    upstream flask {
        server 172.19.16.191:5000;
        server 172.19.16.191:5001;
    }

    server {
        listen       80;
        server_name  localhost;

        location / {
            proxy_pass   http://flask;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }

    include servers/*;
}

2)启动命令
gunicorn -w 2 -b 172.19.16.191:5000 --access-logfile ./logs/log app:app
gunicorn -w 2 -b 172.19.16.191:5001 --access-logfile ./logs/log2 app:app

33.常见网络攻击

1)xss:跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意脚本代码,而程序对于用户输入内容未过滤,当用户浏览该页之时,嵌入其中Web里面的脚本代码会被执行,从而达到恶意攻击用户的特殊目的。
    解决方案:利用HTMLParser去除request请求体数据
from html.parser import HTMLParser


class StripTagsHTMLParser(HTMLParser):
    data = ""

    def handle_data(self, data):
        self.data += data

    def getData(self):
        return self.data


parser = StripTagsHTMLParser()
parser.feed('<script src="https://123.js" async="">123</script>')
data = parser.getData()
print(data)
2)csrf:登陆后没有退出,浏览器保留了登陆信息cookie和session等,同时这个正常的网站没有对登陆状态进行进一步的安全校验,
    然后用户又去浏览其他恶意网页,其他恶意网站有直接请求原正常网站的恶意请求,造成恶意攻击,删除修改内容,购买商品等
    解决办法:尽量使用post请求;加入验证码;验证referer(验证请求发送的地址是否为当前地址);csrf token(form表单存token,后端验证,验证后失效);header中加入验证信息,验证信息从页面form表单中取,类似token
# flask处理方式
from flask_wtf.csrf import CsrfProtect
csrf = CsrfProtect()
 
def create_app():
  app = Flask(__name__)
  csrf.init_app(app)
3)sql注入:就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令
    解决办法:使用orm;对参数进行严格校验;使用mysql存储过程;敏感信息加密
4)DDOS攻击:控制多个真实主机模拟真实用户进行集中访问某个接口,造成服务器压力过大,导致服务崩溃
    解决办法:基本没法防御
5)Cookie攻击:通过js获取cookie,然后利用cookie冒充用户进行访问
    解决办法:现在多数浏览器都支持在cookie上打上HttpOnly的标记,凡有这个标志的cookie就无法通过Java Script来取得,如果能在关键cookie上打上这个标记,就会大大增强cookie的安全性。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值