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.form、request.args、request.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
~~~