Flask

Python 现阶段三大主流Web框架 Django Tornado Flask 对比:

  Django 主要特点是大而全,集成了很多组件,例如: Models Admin Form 等等, 不管你用得到用不到,反正它全都有,属于全能型框架
  Flask 主要特点小而轻,原生组件几乎为0, 三方提供的组件请参考Django 非常全面,属于短小精悍型框架
  Tornado 优点是异步,用于游戏服务后台,缺点是干净,连个Session都不支持

  flask和django最大的不同点:request/session 是需要单独导入的

 

flask知识点:

  - 模板+静态文件,app= Flask(__name__,....)
  - 路由 
    @app.route('/index',methods=["GET"])
  - 请求 
    request.form
    request.args
    request.method
  -响应

    render
    redirect
  -session

    session['xx'] = 123
    session.get('xx')

Flask初级实现:

from flask import Flask   #Flask是个类

#传参实例化Flask,拿到一个对象app
app = Flask(__name__)

@app.route('/index')  #路由和下面函数绑定,@后面写上面实例化对象的名字
#写一个函数,return一个结果
def index():
    return "hello word-flask"

#调用里面的run方法
app.run()

 优化为:

from flask import Flask   #Flask是个类

#传参实例化Flask,拿到一个对象app
app = Flask(__name__)

@app.route('/index')  #路由和下面函数绑定,@后面写上面实例化对象的名字
#写一个函数,return一个结果
def index():
    return "hello word-flask"

#调用里面的run方法
if __name__ == '__main__':
    app.run()

知识点一:用到的知识点有rsplit::切分 、getattr:返回对象属性值 、dir:返回模块的属性列表

通过给定一个字符串路径,找到对应的类及类里面的属性和属性值

例如:- 给你一个路径 “settings.Foo”,可以找到类并获取去其中的大写的静态字段。

test.py里面的设置

import importlib

path = 'settings.Foo'
p,c =path.rsplit('.',maxsplit=2)  #maxsplit代表切分几次
# print(p,c) #settings Foo
#拿到settings所在的路径
m=importlib.import_module(p) #<module 'settings' from 'E:\\知识点练习\\知识点回忆\\settings.py'>

#getattr返回对象属性值
cls=getattr(m,c)
print(cls) #<class 'settings.Foo'>

"""例如下面:
>>>class A(object):
...     bar = 1
... 
>>> a = A()
>>> getattr(a, 'bar')        # 获取属性 bar 值

"""
#如何找到这个类
#dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。
# print(dir(cls)) #['DEBUG', '__class__', '__delattr__',...]
for key in dir(cls):
    if key.isupper():
        #DEBUG True 最终拿到类中属性及属性值
        print(key,getattr(cls,key))
根据字符路径找内容

配置文件:查看、修改

settings.py设置:设置配置文件参数

#通过settings文件,完成对app.config配置文件的修改
#分类,方便app里面不同的应用场景调用

#共同需要的配置写在基类里面,下面单独修改的部分去继承这个基类
class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite://:memory:'

# 开发环境
class DevelopmentConfig(Config):
    DEBUG = True


#上线环境
class ProductionConfig(Config):
    DATABASE_URI = 'mysql://user@localhost/foo'


class TestingConfig(Config):
    TESTING = True

app.py配置:引用settings配置文件,实现查看、修改

from flask import Flask,render_template,redirect,request

app=Flask(__name__)

#查看配置文件
print(app.config)

#修改配置文件
#方式一:单独修改一项
# app.config['DEBUG'] = True

#方式二:批量修改,from_object后面是个字符串(根据字符串找到settings类,在类里面统一去做一些修改)
app.config.from_object("settings.DevelopmentConfig")  #根据需求调用settings配置文件里面的类

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

路由系统:

首先,要导入url_for: from flask import url_for

近而,通过url_for反向生成url地址

静态路由:无参数、反向解析endpoint

@app.route('/index/123/456',methods=['GET','POST'],endpoint='n1')  #endpoint='n1'类似于Django里面的name,用于反向解析
def index():
    # 通过url_for 反向生成url
    print(url_for('n1'))  #/index/123/456
    # 如果不指定endpoint='n1',默认写路由对应装饰的函数的名字
    print(url_for('index')) #/index/123/456
    
     user=session.get('user')
    # print(session)  session类似个字典(里面包含的用户名信息):    
    <SecureCookieSession {'user': 'yzz'}>
    if not user:
        return redirect('/login')
    return render_template('index.html')

 

动态路由:有参数、也可以搭配反向解析使用

#动态路由(<int:nid>)index要接收nid
@app.route('/index/<int:nid>', methods=['GET', 'POST'])  # endpoint='n1'类似于Django里面的name,用于反向解析
def index(nid):
    print(nid) #拿到的时你实际浏览器输入的值
    #url_for 有参数就传参数,没参数就写endpoint的值
    print(url_for('index',nid=733)) #/index/733

    user=session.get('user')
    # print(session)  session类似个字典(里面包含的用户名信息):<SecureCookieSession {'user': 'yzz'}>
    if not user:
        return redirect('/login')
    return render_template('index.html')

FBV:

请求与响应:

#请求与响应
# 请求相关信息
        request.method
        request.args
        request.form
        request.values
        request.cookies
        request.headers
        request.path
        request.full_path
        request.script_root
        request.url
        request.base_url
        request.url_root
        request.host_url
        request.host
        request.files
        obj = request.files['the_file_name']
        obj.save('/var/www/uploads/' + secure_filename(f.filename))

# 响应:
        # 响应体:
        第一种:return “asdf”
        第二种:return jsonify({'k1': 'v1'})  #jsonify将字典转为字符串返回
        第三种:return render_template('xxx.html')
        第四种:return redirect()


        # 定制响应头:例如第一种方式
        obj = make_response("asdf")  #设置个响应体
        obj.headers['xxxxxxx'] = '123'  #设置个响应头 响应头里面会增加一项:xxxxxxx:123
        obj.set_cookie('key', 'value')   #设置cookies 响应头里面会增加一项:Set-Cookie:key=value; Path=/
        return obj

实例:

版本一:学生管理-简单登录、删除、查看

from flask import Flask
#导入三大组件:render_template模板渲染  redirect重定向
from flask import render_template,request,redirect,session,url_for,jsonify,make_response

app = Flask(__name__,template_folder="templates",static_folder="static") #默认后台文件夹的名字

#需要加盐(因为flask的session是放在本地cookie里面的,只不过是加密),也可以添加在app.settings配置里面
app.secret_key = 'fjsjflks'

# 修改配置文件
app.config.from_object("settings.DevelopmentConfig")  #根据需求调用settings配置文件里面的类


STUDENT_DICT = {
    1:{'name':'张三','age':12,'gender':''},
    2:{'name': '李四', 'age': 34, 'gender': ''},
    3:{'name': '王五', 'age': 45, 'gender': ''},
}

#路由配置
@app.route('/login',methods=['GET','POST'])
def login():
    if request.method=="GET":
        # return 'login'
        return render_template('login.html')

    user = request.form.get('user')
    pwd = request.form.get('pwd')
    if user == 'yzz' and pwd == '123':
        session['user'] = user
        return redirect('/index')

    return render_template('login.html', error='用户名或密码错误')


#静态路由(无参数)
@app.route('/index')
def index():
    user = session.get('user')

    if not user:
        return redirect('/login')
    return render_template('index.html',stu_dic=STUDENT_DICT)

@app.route('/delete/<int:nid>')  #接收前端点击,对应的nid,战队nid进行删除
def delete(nid):
    user = session.get('user')

    if not user:
        # return redirect('/login')
        return redirect(url_for('login'))

    del STUDENT_DICT[nid]
    return redirect(url_for('index'))

@app.route('/detail/<int:nid>')
def detail(nid):
    user = session.get('user')

    if not user:
        return redirect('/login')
    info = STUDENT_DICT[nid]
    return render_template('detail.html',info=info)


if __name__ == '__main__':

    app.run()
主文件app.py
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <h1>用户登录</h1>
    <form method="post">
        <input type="text" name="user">
        <input type="password" name="pwd">
        <input type="submit" value="提交">{{error}}
    </form>
</body>
</html>
登录lgin.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <h1>学生列表</h1>
    <table border="1px">
        <thead>
            <tr>
                <th>ID</th>
                <th>姓名</th>
                <th>年龄</th>
                <th>性别</th>
                <th>选项</th>
            </tr>
        </thead>

        <tbody>
            {% for k,v in stu_dic.items()%}
                <tr>
                    <td>{{k}}</td>
                    <td>{{v.name}}</td>
                    <td>{{v.age}}</td>
                    <td>{{v.gender}}</td>
                    <td>
                        <a href="/detail/{{k}}">查看详情</a> |
                        <a href="/delete/{{k}}">删除</a>
                    </td>


                </tr>
            {%endfor%}
        </tbody>



    </table>

</body>
</html>
学生信息一览index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>学生详情</title>
</head>
<body>
    {% for item in info.values()%}
        <li>{{item}}</li>
    {%endfor%}

</body>
</html>
单个学生详情detail.html

版本二:认证装饰器-基于functools模块(应用于比较少的函数中需要额外添加功能)

from flask import Flask
#导入三大组件:render_template模板渲染  redirect重定向
from flask import render_template,request,redirect,session,url_for,jsonify,make_response

app = Flask(__name__,template_folder="templates",static_folder="static") #默认后台文件夹的名字

#需要加盐(因为flask的session是放在本地cookie里面的,只不过是加密),也可以添加在app.settings配置里面
app.secret_key = 'fjsjflks'

# 修改配置文件
app.config.from_object("settings.DevelopmentConfig")  #根据需求调用settings配置文件里面的类


STUDENT_DICT = {
    1:{'name':'张三','age':12,'gender':''},
    2:{'name': '李四', 'age': 34, 'gender': ''},
    3:{'name': '王五', 'age': 45, 'gender': ''},
}

#登录认证装饰器
import functools
def auth(func):
    @functools.wraps(func)
    def innder(*args,**kwargs):
        if not session.get('user'):
            return redirect(url_for('login'))
        ret = func(*args,**kwargs)
        return ret
    return innder


#路由配置
@app.route('/login',methods=['GET','POST'])
def login():
    if request.method=="GET":
        # return 'login'
        return render_template('login.html')

    user = request.form.get('user')
    pwd = request.form.get('pwd')
    if user == 'yzz' and pwd == '123':
        session['user'] = user
        return redirect('/index')

    return render_template('login.html', error='用户名或密码错误')


#静态路由(无参数)
@app.route('/index')
@auth
def index():

    return render_template('index.html',stu_dic=STUDENT_DICT)
print(index.__name__)

@app.route('/delete/<int:nid>')  #接收前端点击,对应的nid,战队nid进行删除
@auth
def delete(nid):

    del STUDENT_DICT[nid]
    return redirect(url_for('index'))
print(delete.__name__)

@app.route('/detail/<int:nid>')
@auth
def detail(nid):

    info = STUDENT_DICT[nid]
    return render_template('detail.html',info=info)
print(detail.__name__)

if __name__ == '__main__':

    app.run()

版本三:认证装饰器-基于@app.before_request(应用于需要装饰的方法较多时)

@app.before_request
def xxxx():
    if request.path == '/login':
        return None   #return None,表示允许通过,继续显示相应页面
    if session.get('user'):
        return None

    return redirect('/login')
from flask import Flask
#导入三大组件:render_template模板渲染  redirect重定向
from flask import render_template,request,redirect,session,url_for,jsonify,make_response

app = Flask(__name__,template_folder="templates",static_folder="static") #默认后台文件夹的名字

#需要加盐(因为flask的session是放在本地cookie里面的,只不过是加密),也可以添加在app.settings配置里面
app.secret_key = 'fjsjflks'

# 修改配置文件
app.config.from_object("settings.DevelopmentConfig")  #根据需求调用settings配置文件里面的类


STUDENT_DICT = {
    1:{'name':'张三','age':12,'gender':''},
    2:{'name': '李四', 'age': 34, 'gender': ''},
    3:{'name': '王五', 'age': 45, 'gender': ''},
}


@app.before_request
def xxxx():
    if request.path == '/login':
        return None   #return None,表示允许通过,继续显示相应页面
    if session.get('user'):
        return None

    return redirect('/login')


#路由配置
@app.route('/login',methods=['GET','POST'])
def login():
    if request.method=="GET":
        # return 'login'
        return render_template('login.html')

    user = request.form.get('user')
    pwd = request.form.get('pwd')
    if user == 'yzz' and pwd == '123':
        session['user'] = user
        return redirect('/index')

    return render_template('login.html', error='用户名或密码错误')


#静态路由(无参数)
@app.route('/index')
def index():

    return render_template('index.html',stu_dic=STUDENT_DICT)


@app.route('/delete/<int:nid>')  #接收前端点击,对应的nid,战队nid进行删除
def delete(nid):

    del STUDENT_DICT[nid]
    return redirect(url_for('index'))


@app.route('/detail/<int:nid>')
def detail(nid):

    info = STUDENT_DICT[nid]
    return render_template('detail.html',info=info)


if __name__ == '__main__':

    app.run()
app.py详细配置

 

Flask中的三剑客:Render_template Redirect HttpResponse:

  HttpResponse:就是直接返回字符串

  Redirect:网页跳转重定向

  Render_template:使用时需要再主目录中加入一个templates 目录(否则会报一个jinjia2...的异常)

 

Request:

注意点:

  1.解释一个 @app.route("/req",methods=["POST"]) :
    methods=["POST"] 代表这个url地址只允许 POST 请求,是个列表也就是意味着可以允许多重请求方式,例如GET之类的
  2.Form表单中传递过来的值 使用 request.form 中拿到
  3.Flask 的 request 中给我们提供了一个 method 属性里面保存的就是前端的请求的方式

  4.request.args 与 request.form 的区别就是:
    request.args:是获取url中的参数
    request.form :是获取form表单中的参数
  5.request.values :只要是个参数我都要

  6.reuquest.cookies:将cookie信息读取出来

  7.request.headers:拿出请求头中的的秘密

  8.request.files:拿到的是你上传的文件

  9. request.json 之 前提你得告诉是json

   如果在请求中写入了 "application/json" 使用 request.json 则返回json解析数据, 否则返回 None

request.files:

html配置:
<form method="post" action="" enctype="multipart/form-data"> #注意上传文件要配置enctype

    <p>用户名<input type="text" name="username"></p>
    <p>用户名<input type="password" name="password"></p>
    <p><input type="file" name="file"></p>
    <p><input type="submit" value="提交"></p>
    <p>
         {{ msg }}
    </p>


</form>

打印输出:
print(request.files)
验证结果:
ImmutableMultiDict([('file', <FileStorage: '011.docx' ('application/vnd.openxmlformats-officedocument.wordprocessingml.document')>)])

上面request其他的验证:

from flask import Flask,render_template,redirect,request
app=Flask(__name__)

@app.route("/index")
def index():

    print(request.args) #ImmutableMultiDict([('id', '1'), ('age', '30')])
    return "Hello Flask,Welcome you"


@app.route("/login",methods=("POST","GET"))
def login():
    if request.method == "POST":

        # 它看起来像是的Dict
        print(request.form)  #ImmutableMultiDict([('username', 'yzz'), ('password', 'yzz')])
        # print(request.form.keys())  #<dict_keyiterator object at 0x042FF5A0>
        # print(list(request.form.keys())) #['username', 'password']


        username=request.form.get('username') #yzz
        password=request.form.get('password')
        if username == 'yzz' and password == 'yzz':
            return redirect('/index')
        else:
            return render_template("template.html",msg="密码错误")

    return render_template("template.html", msg=None)
app.run(debug=True)

 

模板渲染:

查看学生信息:就向后端传入字典、列表(套字典)、字典(套字典)

from flask import Flask,render_template,redirect,request
app=Flask(__name__)

#格式一
STUDENT = {'name': 'Old', 'age': 38, 'gender': ''},

'''
templates设置:
return render_template("stu.html",student=STUDENT)
路由函数设置:
{{student}}

'''

#格式二
STUDENT_LIST = [
    {'name': 'Old', 'age': 38, 'gender': ''},
    {'name': 'Boy', 'age': 73, 'gender': ''},
    {'name': 'EDU', 'age': 84, 'gender': ''}
]

'''
templates设置:
<table border="1xp">
        {% for foo in student %}
            <tr>
                <td>{{ foo.name }}</td>
                <td>{{ foo.get("age") }}</td>
                <td>{{ foo["gender"] }}</td>
            </tr>
        {% endfor %}
</table>

路由函数设置:
return render_template("stu.html",student=STUDENT_LIST)

'''

#格式三
STUDENT_DICT = {
    1: {'name': 'Old', 'age': 38, 'gender': ''},
    2: {'name': 'Boy', 'age': 73, 'gender': ''},
    3: {'name': 'EDU', 'age': 84, 'gender': ''},
}
'''
templates设置:
<table border="1xp">
        {% for k,v in student.items() %}
            <tr>
                <td>{{ v.name }}</td>
                <td>{{ v.get("age") }}</td>
                <td>{{ v["gender"] }}</td>
            </tr>
        {% endfor %}
</table>
路由函数设置:
return render_template("stu.html",student=STUDENT_DICT)

'''

 return_template也可以传递多个值:

@app.route("/allstudent")
def all_student():
    return render_template("all_student.html", student=STUDENT ,
                           student_list = STUDENT_LIST,
                           student_dict= STUDENT_DICT)

 

Jinja2中的safe用法(xss攻击有关,如何显示html代码让浏览器识别定执行),结果输出就不是字符串,而是执行后的网页渲染效果

正常网页显示结果:

  <input type='text' name='user' value='DragonFire'>  #普通字符串格式

 

为了让浏览器能够识别并执行这个html代码,可以通过以下2中方式实现;

方式一:前端加safe实现

<body>
    <!--方式一:-->
    {{ tag | safe }}
</body>

方式二;后端导入Markup,实现

from flask import Markup

@app.route("/index")
def index():
    #方式二:
    #导入Markup
    from flask import Markup
    tag = "<input type='text' name='user' value='DragonFire'>"
    markup_tag=Markup(tag)

    print(markup_tag,type(markup_tag)) #<input type='text' name='user' value='DragonFire'> <class 'markupsafe.Markup'>

    return render_template("index.html", tag=markup_tag)

 

posted @ 2018-10-05 11:16  yangzhizong  阅读(196)  评论(0编辑  收藏  举报