Flask:初识(返回值、request、Jinjia2语法、session)


flask 初识

一、flask 中的 返回值

示例:一个简单的 flask 项目的启动

  该框架的返回值主要包括5类( 字符串、重定向、页面、json数据、文件(图片和视频)等  )

from flask import Flask, redirect, render_template,json,jsonify,send_file

app = Flask(__name__)


@app.route("/")
def index():
    # return "hello"                 # 返回字符串直接返回即可
    return redirect("/login")      # 重定向


@app.route('/login',methods=["POST","GET"])   # 不写methods,默认是GET请求, def home():
    return render_template('login.html')  # 返回html页面,template设置为 mark derectory


@app.route('/json')
def jsons():
    l = {'name':'cheney'}
    # return json.dumps(l)      # 响应头:Content-Type: text/html; charset=utf-8 ()
    return jsonify(l)        # 响应头:Content-Type: application/json(返回json标准的字符串 )两者是响应头的区别,前端能够识别


@app.route('/file')
def file():
    # return send_file('01.mp4')    # send_file(),打开文件并返回文件内容(自动识别文件格式)
    return send_file('22.png')    # 返回的是图片,二进制文件时,背景是特殊颜色

app.run("0.0.0.0",5000,debug=True)      # 设置debug=True,修改代码,项目可以不重启,如果里面不写参数,默认是127.0.0.1:5000端口的

二、flask 中的 request 

  request,是公共变量

from flask import request

request.method    # 请求方式 'POST' 'GET'

request.form      # 存放FormData中的数据 to_dict 序列化成字典("username":"chen","password":"123"),表单数据提交的都是formdata类型的
 
request.args      # 获取URL中的数据 to_dict 序列化成字典 (get请求中的参数,问号之后的)

request.files     # 序列化文件存储 save()

request.url       # 访问的完整路径  http://127.0.0.1:8000/login   有参数包括参数 ?a=1&b=2

request.path      # 路由地址  (/login)

request.host      # 主机地址   (127.0.0.1:8000)

request.values    # 获取 FormData and URL中的数据,不要用to_dict,会覆盖

request.json      # 如果提交时请求头中的Content-Type:application/json 字典操作

request.data      # 如果提交时请求头中的Content-Type 无法被识别 将请求体中的原始数据存放 byte

request.cookies   # 获取Cookie中的数据

request.headers   # 获取请求头

 

文件的保存:

my_file = request.files.get("my_file")
my_file.save(my_file.filename)   # 可以用原文件的名字,也可以用自己定义的名字和路径,'./chen',当前路径

 

三、Jinja2 语法

flask 中的 Jinja2 类似于 django 中的模板语法(template),两者做的事情是一样的,都是将后端传的内容在前端页面进行渲染

不同的是:

  Jinjia2 用法类似python,取值符合字典列表的规则

  template 用法都是用点 . 取值

1、变量的取值

  {{  }}

    取值类似字典,{{ stu.name }} 、{{ stu[name] }}、{{ stu.get(name) }} 都可以获取值,django中模板语法只能用 点 取值

2、逻辑代码

  {%  %}

3、渲染标签,安全标签字符串

  标签字符串 | safe

  Markup()

4、全局的

  @app.template_global()

5、过滤的

  @app.template_filter()

6、宏 macro 用处不大,定义函数,了解即可

 

示例: 

  后端  ss.py

from flask import Flask, render_template, Markup

app = Flask(__name__)

tag = "<input type='text' name='username'>"
tag = Markup(tag)           # 类似于django中的 Marksafe(),这里用了,前端就不用 tag|safe  了


def func1(a, b):
    return a + b


@app.template_global()
def func(a, b):         # 类似func1,如果多个页面中都要用到func函数,那么就需要每个路由函数都传值函数名,比较麻烦,
                        # 因此使用,template_global()即可,设为全局的
    return a + b


@app.template_filter()
def filter(a, b, c):    # 过滤器函数,template_filter(),也是全局的,不需要传值,模板中直接用即可
    print(a)
    return a + b + c


@app.route("/")
def index():
    return render_template("index2.html", tag=tag, func1=func1)     # func1不是全局的,需要传值


app.run(debug=True)

 

  前端   index2.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> {{ tag }} {{ func1(3,3) }} {{ func(5,5) }} {{ 10 | filter(2,3) }}

{% macro create_input(na,ty) %}
    {{ na }} : <input type="{{ ty }}" name="{{ na }}">
{% endmacro %}
{{ create_input("username","text") }}

</body>
</html>

四、flask 中的 session(利用装饰器验证登录)

1、装饰器的用法

  装饰器主要是用于对某些程序在运行执行做一些处理操作,

  示例:利用装饰器,计算程序运行的时间 

import time


def waibu(func):
    def neibu(*args, **kwargs):
        start = time.time()
        ret = func(*args, **kwargs)
        end = time.time()
        print(end - start)
        return ret

    return neibu


@waibu
def func():
    for i in range(100000000):
        continue
    return "OK"


print(func())  # 1.7812395095825195    # OK

 

2、Flask-Session

  session也是公共变量

  session是用于验证用户身份信息的,可以在登录的时候添加session,访问其他页面的时候校验用户身份信息。

    django:session是存储在服务端的,

    flask:session是加密后存储在前端的cookies中的键值对,节省flask的开销,

       由于Flask中默认Session 存放位置 - 客户端的Cookies中,加密使用 app.secret_key = "加密字符串" ,加密字符串可以随便写,主要是用于序列化和反序列化 session信息,

  • 有人说,session放在前端cookies中,会不完全?

    由于在加密的时候,该加密方式是添加了字符串的,再进行加密,而字符串是保存在后端的,因此,别人不知道字符串自然也无法解密

  • 请求进入视图函数 带上cookie 将Session从cookie序列化出来 通过secret_key 反序列化成字典

xxx.py

from flask import Flask, redirect, render_template, request, session

app = Flask(__name__)
app.secret_key = "DragonFire"  # 这里一定要给定字符串,进行加密

@app.route("/login", methods=["POST", "GET"])    # 在涉及到其他请求的时候,一定要添加进来,不写则请求不能访问,默认是GET,如果只有GET访问的话可以不写 def login():
    if request.method == "GET":
        return render_template("login.html")

    if request.form.get("username") == "chen" and request.form.get("password") == "123":
        session["user"] = request.form.get("username")   # 登录成功,将用户信息添加到session中 ,访问其他路由的时候,通过session进行验证即可。

       return redirect("/")


app.run(debug=True)

 login.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>
<form action="" method="post" enctype="multipart/form-data">
  用户名<input type="text" name="username">
  密码<input type="password" name="password">
  文件:<input type="file" name="my_file">
  <input type="submit" value="登录">
</form>
</body>
</html>
View Code

 

3、利用装饰器验证session,进行用户登录

  示例:

from flask import Flask, redirect, render_template, request, session

app = Flask(__name__)
app.secret_key = "DragonFire"


@app.route("/login", methods=["POST", "GET"])  # 登录不能加装饰器,验证session
def login():
    if request.method == "GET":
        return render_template("login.html")

    if request.form.get("username") == "chen" and request.form.get("password") == "123":
        session["user"] = request.form.get("username")
        print(session['user'])
        print(11)

        return redirect("/index")


def wai(func):                        # 验证session信息的装饰器函数
    def nei(*args, **kwargs):
        if session.get("user"):            # session取值,不要使用所以["user"]取值,因为不确定时候有键,没有会报key-error错误
            ret = func(*args, **kwargs)
            return ret
        else:
            return redirect("/login")

    return nei


@app.route("/",methods=['GET'],endpoint='hello')   # 不指定endpoint的函数名,会报错,装饰器不能使用,另外装饰器(@wai)要放在下面
@wai                                                # nei = wai(hello) def hello():
    return  'hello'


@app.route("/index",methods=['GET'],endpoint='index')
@wai                                               # nei = wai(index) def index():
    # if not session.get("user"):        # 可以再每个函数中进行session身份信息的验证,但是比较麻烦,会有代码的重复
    #     return redirect("/login")
    return render_template("index.html")


app.run(debug=True)

   总结:

    1、装饰器函数修饰要放在@app.route() 的下面

    2、使用装饰器@wai,没有在@app.route()中指明 endpoint的路由函数,装饰器是不能使用的,会报一下错误

        AssertionError: View function mapping is overwriting an existing endpoint function: nei

      为什么会出现这种问题?

使用Flask定义URL的时候,如果出现"AssertionError: View function mapping is overwriting an existing endpoint function"这个异常信息,就说明定义了多个同名的视图函数,只需要改成不同的函数名即可。
这是为什么呢?

原来flask中url跟视图函数并不是直接对应的,而是有一个中间者-endpoint。

三者之间的关系是这样的:

```
url---->endpoint---->view_function
```

它们是一对一的关系,在注册add_url_rule的时候,如果不指定endpoint,那么endpoint就会默认为函数名字,如果同一个endpoint于多个url注册的话,就会发生冲突,从而抛出异常。

     3、解决办法就是:在route中指明 endpoint="路由函数名"

      方式一:在route中指明 endpoint="路由函数名",上面的示例采用的是该方式

                           

        源码中解析:

           如果不指定endpoint,那么会默认是传入@app装饰器的原函数,这里也就是@wai 装饰后的函数名 nei,多个函数都装饰的时候就会重复,所以会报错

       

 

       方式二、利用functools保持原来的函数名

         

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM