flask基础1

flask与Django对比

1、Django组件多,功能全,但在项目启动时会加载所有的组件——项目大的话占用资源比较高——项目运行时间长的话会有许多的无用资源——需要用python的垃圾回收机制回收。。。

2、flask支持多线程的能力很弱,Django处理多线程能力强;flask三方组件全(但存在版本兼容问题不稳定)

flask项目的写法

以一个简单的登陆程序来讲~

项目的目录结构如下:

flask1.py的内容如下:

# -*- coding:utf-8 -*-
import os

from flask import (Flask,jsonify,render_template,
                   request)

# 实例化一个Flask类对象
app = Flask(__name__)

# debug模式——代码热加载,修改完后台代码后不用重启项目了
# 注意线上不要用debug模式!
app.config['DEBUG'] = True


@app.route('/login',methods=['POST','GET'])
def login():
    msg_dic = {'msg':'欢迎来到火之国'}
    if request.method == 'GET':
     # 给模板中传数据直接赋值,注意跟django不一样
return render_template('login.html',mdic=msg_dic) elif request.method == 'POST': # 用form属性取表单的值 uname = request.form.get('username') pwd = request.form.get('password') if uname == 'naruto' and pwd == 'sasuke': return '登陆成功' else: return '登陆失败' if __name__ == '__main__': # 项目的根目录 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 运行flask项目 指定ip与端口 app.run('127.0.0.1',5678)

login.html的内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陆</title>
</head>
<body>
<h1 style="color:red;">{{ mdic.msg }}</h1>
<form action="" method="post">
    username: <input type="text" name="username">
    password: <input type="password" name="password">
    <button>登陆</button>
</form>

</body>
</html> 

flask请求(request)的相关方法 *****

重点掌握: request.formrequest.argsrequest.files!注意获取url的那几个!

print(request.method)  # 获取请求方式
print(request.form) # post方式提交数据的话可以取到~注意key是后台的name属性的值 ImmutableMultiDict([('username', 'whw'), ('password', '123')])

# 特别注意:想要在浏览器的地址栏加参数的话,视图函数中的路径需要这样写:'/login/'
# 浏览器中输入:http://127.0.0.1:5678/login/?name=whw&age=18
print(request.args) # ImmutableMultiDict([('name', 'whw'), ('age', '18')]) —— 不可更改!使用 request.args.to_dict()方法可以转换为可更改的字典!
print(request.args.get("id"))  # 获取URL中的参数
print(request.args["id"])  # 获取URL中的参数
print(request.args.to_dict())  # 获取URL中的参数 转换成 字典

print(request.files) # 文件上传都在这里~后面有一个例子

print(request.path) # /login
print(request.url) # 全路径~ http://127.0.0.1:5678/login/?name=whw&age=18
print(request.base_url) # 获取URL头,不包含参数~http://127.0.0.1:5678/login/

print(request.environ)  # 获取请求原始信息 

print(request.json)  # 请求头中 Content-type:application/json 数据序列化 request.json
print(request.data)  # 请求头中 Content-type 不包含 Form or data

print(request.headers)  # 请求头中的数据

flask响应(response)的相关方法 *****

1、直接给返回一个字符串 —— 类似于django的HttpResponse方法

2、返回一个字典时需要注意版本问题(下面有专门的说明)

3、返回一个标签字符串的话需要再引入 Markup模块

4、render方法返回一个页面 —— 传参数的话跟django不一样(详见下面模板那部分)

5、redirect方法里面跟一个固定的路径

Pycharm中给模板“备注”为jinjia2——以后写模板的时候有提示了

右键点击新建的templates文件夹——Mark Directory as Template——Template Forder——选yes——再在里面选jinjia2(Django的话选django)

flask的版本与处理json序列化数据的问题

结论:在flask1.1.1开始视图函数可以直接返回一个字典!但是在此版本之前只能用jsonify方法返回字典! 

1.1.1版本之前只能用jsonify方法返回字典

上面上报的错误是:TypeError

1.1.1版本的flask可以直接返回字典

可以访问index看一下结果:

文件上传的方法 *****

后台代码如下:

# -*- coding:utf-8 -*-
import os

from flask import (Flask,jsonify,render_template,
                   request)
# 实例化一个Flask对象
app = Flask(__name__)

# debug模式——代码热加载,修改完后台代码后不用重启项目了
# 注意线上不要用debug模式!
app.config['DEBUG'] = True


# 如果有表单提交数据的话,必须指定methods列表里面有GET与POST方法!
@app.route('/file',methods=['GET','POST'])
def put_file():
    if request.method == 'GET':
        return render_template('put_file.html')

    elif request.method == 'POST':
        # 获取上传的文件
        file_put = request.files.get('my_file')
        # 上传的目录是项目的media目录里
        # file_put的filename属性可以取出文件的名称
        file_path = os.path.join(BASE_DIR,'media',file_put.filename)
        try:
            # 将文件保存在对应的位置,save方法
            file_put.save(file_path)
            return '上传成功'
        except Exception as e:
            print(e)
            return '上传失败'

if __name__ == '__main__':
    # 项目的根目录
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    # 运行flask项目
    app.run('127.0.0.1',5678)

项目的模板文件如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
</head>
<body>

{# 上传文件的话~~这里必须指定enctype!!! #}
<form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="my_file">
    <button>上传</button>
</form>

</body>
</html>

启动项目后访问 http://127.0.0.1:5678/file 就可以了~

特别说明:

# 如果访问文件的地址的话
打开并返回文件内容,
自动识别文件类型,
响应头中加入Content-type:文件类型
ps:当浏览器无法识别Content-type时,会下载文件

405错误说明

405错误表示请求方式不被允许,需要修改一下请求的方式!

一般出现这种错误的情景是:

(1)GET与POST请求的方法混了——需要修改一下代码的请求方法;

(2)第二种情况是在flask的装饰器的methods列表中没有写POST,如果用POST提交的话也会报这个错误!

flask中的session操作 *****

注意~~flask自带的session是存在了本地cookie中!

反序列化机制与序列化机制

反序列化机制——生成session

  客户端发起请求(request)会带上cookie。cookie中包含session的加密字符串,flask收到这个加密的字符串后,通过secret_key解密session的加密字符串,最终获得session中的数据。

  注意里面的时间戳只是用来计算“超时时间”的,默认是31天——在app.default_config中可以查看具体的属性的~(app是Falsk实例化的对象Flask(__name__) )

序列化机制——查找session

  先创建一个字典(比如{'username':'wanghw'}),接下来通过之前设置好的secret_key当前时间的时间戳签名加密生成密文,存放在本地cookie中。

实例

后台逻辑:

# -*- coding:utf-8 -*-

from flask import Flask,session,request,render_template

app = Flask(__name__)
app.debug = True

# 用session必须设置一个secret_key
app.secret_key = '6srwesfsdfqw'


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

    elif request.method == 'POST':
        uname = request.form.get('username')
        pwd = request.form.get('password')

        if uname == 'whw' and pwd == '123':
            # 登陆成功后设置session
            session['username'] = uname
            return 'OJ8K'
        else:
            return 'ERROR'


@app.route('/detail')
def detail():
    # 获取session
    if session.get('username'):
        return '成功获取session'
    else:
        return 'NONONO'


if __name__ == '__main__':
    app.run('127.0.0.1','6789')

登陆的页面很简单,跟之前一样:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陆</title>
</head>
<body>

<form action="" method="post">
    username: <input type="text" name="username">
    password: <input type="password" name="password">
    <button>登陆</button>
</form>

</body>
</html>

jinjia2模板的练习 ***

flask前端模板用的是jinjia2

传入固定的字典、列表套字典、字典套字典

后台的写法

# -*- coding:utf-8 -*-
from flask import Flask,render_template

app = Flask(__name__)
app.config['DEBUG'] = True


STUDENT = {'name': 'www', 'age': 38, 'gender': ''},

STUDENT_LIST = [
    {'name': 'whw1', 'age': 38, 'gender': ''},
    {'name': 'whw2', 'age': 73, 'gender': ''},
    {'name': 'whw3', 'age': 84, 'gender': ''}
]

STUDENT_DICT = {
    1: {'name': 'whw1', 'age': 38, 'gender': ''},
    2: {'name': 'whw2', 'age': 73, 'gender': ''},
    3: {'name': 'whw3', 'age': 84, 'gender': ''},
}

@app.route('/index')
def index():
    return render_template('index.html',student_info=STUDENT,stu_list=STUDENT_LIST,student_dic=STUDENT_DICT)

if __name__ == '__main__':
    app.run('127.0.0.1',5678)

前端模板的渲染

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{{ ab(1,2) }}

{# jijia2里面的函数~~生成一个标签 #}
{% macro my_iput(na,ty) %}
    <input type="{{ na }}" value="{{ ty }}">
{% endmacro %}


{{ my_iput('text','123') }}


<table id="t1">
    <thead>
        <tr>
            <td>name</td>
            <td>age</td>
            <td>gender</td>
        </tr>
    </thead>

    <tbody>
        {% for stu in stu_list %}
            <tr>
                <td>{{ stu.name }}</td>
                <td>{{ stu.age }}</td>
                
                <td>
                    {# 如果不是男也不是女 默认是女 #}
                    {% if stu.gender != '' and stu.gender != '' %}
                    女
                    {% else %}
                        {{ stu.gender }}
                    {% endif %}
                </td>
            </tr>
        {% endfor %}
    </tbody>
</table>


<table id="t2">
    <thead>
        <tr>
            <td>name</td>
            <td>age</td>
            <td>gender</td>
        </tr>
    </thead>

    <tbody>
        {# 如果后台是是字典套字典的形式的话~注意values()取到所有的值;items()取到所有简直对 #}
        {# 注意items与values要加括号!!! #}
        {# {% for stu in student_dic.values() %}  #}
        {% for key,stu in student_dic.items() %}
            <tr>
                <td>{{ stu.name }}</td>
                <td>{{ stu.age }}</td>
                {# 如果不是男也不是女 默认是女 #}
                <td>
                    {% if stu.gender != '' and stu.gender != '' %}
                    女
                    {% else %}
                        {{ stu.gender }}
                    {% endif %}
                </td>
            </tr>
        {% endfor %}
    </tbody>
</table>


</body>
</html>=

模板的几个进阶应用

类似于diango的templatetags的一个用法

后台的写法

# -*- coding:utf-8 -*-
from flask import Flask,render_template

app = Flask(__name__)
app.config['DEBUG'] = True### 所有模板都能用到的一个函数~~注意装饰器得加括号
@app.template_global()
def ab(a,b):
    return a+b

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

if __name__ == '__main__':
    app.run('127.0.0.1',5678)

前端模板这样渲染:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{{ ab(1,2) }}

</body>
</html>

结果在页面中会出现:3

jinjia2模板中生成标签的函数~注意是模板中的函数

模板中的语法如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陆</title>
</head>
<body>

{# 定义生成的标签的规则 #}
{% macro my_input(ty,na) %}
  <input type="{{ ty }}" name="{{ na }}">
{% endmacro %}

{# 利用之前的规则生成标签 #}
{{ my_input('text','nana') }}


</body>
</html>

生成的标签如下:

配套的代码在码云

配套的代码在码云:https://gitee.com/huoyingwhw/practice

~~~

posted on 2019-07-10 15:49  江湖乄夜雨  阅读(244)  评论(0编辑  收藏  举报