flask1 + jinja2 day88
人工智能方向 - 智能玩具
-1 所学内容:
1.flask(前后端交互的接口)(返回api(json))
2.MongoDB NoSQL(自由度高,(没什么限制),操作就难)4版本(多了个事务)+3.4
3.人工智能 A.I. 应用技术 Not 算法和机器学习
4.webSocket 全双工通讯 IM即时通讯
5.Mui(布局,布局一个 ) + HTML5Plus(打开硬件有封装) App (工作了,就是一个小儿科,这些框架,质的飞跃)
6.智能玩具 + 机器学习
0 Django 和 Flask 优劣势
Django 15天
优势:组件全 - admin - Model ORM - Forms
教科书式(其他框架和他像)
劣势:加载的组件是全部的组件 - 占用资源较高
重型框架
Flask 3 天
优势:轻如鸿毛 扩展性极强 三方组件全
劣势:什么组件都没有
三方组件全 - 版本兼容问题 导致不稳定
线程的支持(不如dj)
1 flask 初识
1.1 flask 安装+启动
安装
新建pure python项目
-new environment 选择 Virtualenv
--选择interpreter
---选择make available to all projects
启动
在大目录下,新建一个py文件
from flask import Flask #导入Flask以及别的
app=Flask(__name__) #Flask第1个参数 模块名
app.run() #默认访问http://127.0.0.1:5000/ 端口启动也可以指定别的端口
比如:# app.run('0.0.0.0',9527)
Flask 源码:
def __init__(
self,
import_name,
返回错误 503 可以连接,但是没有返回视图
1.2 模板的书写
from flask import Flask,render_template #返回模板
app=Flask(__name__)
@app.route('/') # route() 装饰器 url 触发--> 函数
def home():
# return 1 #不能返回整型
return 'hello world' #可字符,字典,列表
@app.route('/index')
def index():
return render_template('index.html') #来渲染模板。
app.run()
方法:
1 写一个templates
把index.html 放了里面 然后飘黄
2 make dir template dir 选择jinja2 (webpy ,django,等) (Django封装了(要不也可以使用jiaja2了) jinja2最好 )
Flask 会在 templates 文件夹里寻找模板, 之后就可以向django一样使用模板了,自动补全
所以,如果你的应用是个模块,这个文件夹应该与模块同级;如果它是一个包,那么这个文件夹作为包的子目录:
情况 1: 模块:
/application.py
/templates
/hello.html
情况 2: 包:
/application
/__init__.py
/templates
/hello.html
1.3 flask1.1之前使用jsonify
jsonify 模块
from flask import Flask,render_template,jsonify
@app.route('/json')
def my_jsonify():
# return jsonify({'a':1}) #字典转成json字符串
return {'k':1} #1.1后支持直接传字典
return jsonify(username=g.user.username,...
--------》
This will send a JSON response like this to the browser::
{
"username": "admin",...
flask 中的返回特殊封装 2个
1 jsonify 转换标准JSON格式
响应头中加入 Content-type:application/json
app/json 自动的将 转换成object?字典?
flask1.1下 直接返回字典了,可以不用使用jsonify (向下兼容了) (flask之前的的必须使用jsonify,作为一个开发两年的mn)
2 send_file 发送文件
alt + 回车(补全import)
打开并返回文件内容,
自动识别文件类型,
响应头中加入了 Content-Type
前端 : 只和request有关系
所有response都是后端处理的
text image audio/mpeg(MP3) video/mp4(两次请求,http请求数据是有限制的,流媒体,节省服务器资源) my_file my_file
所有浏览器无法识别的东西: 都以下载的格式返回
比如zip格式的 Content-Type: application/x-zip-compressed
爬虫的时候: 采集视频难,一段一段,中间还得带验证码
当我传MP3MP4格式的时候,发现MP3格式的图标是? 而MP4的格式是文本一样(但是可以传说明没问题)
send_file代码如下:(文件都在主目录下)
@app.route('/my_file')
def my_file():
# return send_file('1.png')
# return send_file('app01.py')
# return send_file('1.mp3')
# return send_file('1.mp4')
# return send_file('1.jpg')
return send_file('1.zip')
if name == 'main':
作用:执行的时候才走,被别的调用的时候不走了
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/login')
def login():
return render_template('login.html')
if __name__ == '__main__': # 只有调用的时候才执行 别的文件引入时候不执行
app.run()
2 . request
<h1>login</h1>
<form action="" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="pwd">
<input type="submit" value="登录">
405 : 请求方式不被允许
127.0.0.1 - - [10/Jul/2019 10:32:53] "GET /login HTTP/1.1" 200 -
127.0.0.1 - - [10/Jul/2019 10:33:03] "POST /login HTTP/1.1" 405 -
解决:
@app.route('/login',methods=['POST','GET'])
route允许post和get方法
request是全局的(公共对象),第一个用户进来了,第二个用户也都能用 那就不支持多进程了,有解决方法
request.form 获取FormData的数据 - Form表单
request = LocalProxy(partial(_lookup_req_object, "request"))
if request.method == 'GET': #请求方式
return render_template('login.html')
if request.method == 'POST':
print(request.form)
print(request.form.get('username'))
print(request.form.to_dict())
return '200 OK'
ImmutableMultiDict([('username', 'asdfas'), ('pwd', 'adfasd')]) #多重字典 看到dict用get
2.2 request参数
request.headers #请求头中的数据
request.url #访问路径 http://127.0.0.1:5000/login
request.path#路由地址 /login
综合获取
request.values #获取URL中的参数 也可以获取FormData中的数CombinedMultiDict([ImmutableMultiDict([('id', '1'), ('ids', '2')]), ImmutableMultiDict([('username', '123'), ('pwd', '456')])])
request.values.get('id') #
request.args.to_dict() #获取url参数{'id': '1', 'ids': '2'}
request.args['id']) # key value key没有值会报错,get比较好 比如: KeyError: 'id'
request.args.to_dict()['id']
request.environ #获取请求原始信息 #{'wsgi.version': (1, 0), 'wsgi.url_scheme': 'http', .........}
request.base_url #获取url头,不包含参数 #http://127.0.0.1:5000/login
request.json #请求头con-type:app/json 数据序列化 #None
request.data #请求头中contype 不包含Form or data #b''
request.headers #Host: 127.0.0.1:5000
request.value的坑
由于都是ImmutableMultiDict([('id', '1'),
如果前端提交name写了id 那么.to_dict() 就会被覆盖
先写的dataform后写的url,url覆盖
2. #指定目录保存
默认保存到主目录(项目)下
my_file = request.files.get('my_file')
my_file.save('save.jpg')
fp = os.path.join('templates',my_file.filename) #
my_file.save(fp) #指定目录保存到templates下
区分form和from的方法
Form 表单 - FormData
f orm - 表单
from
2.# 自动重启
django自带的
# app.config['DEBUG'] = True
app.debug = True #避免重启
按ctrl + s 重启
切换也重启
2.# url? 传参
<http://127.0.0.1:5000/login?id=1>
这样访问 ?传输参数 不会对地址路由造成影响 是传参了
3 模板传参的写法
3.1 py 视图
STUDENT = {'name': 'Old', 'age': 38, 'gender': '中'}
STUDENT_LIST = [
{'name': 'Old', 'age': 38, 'gender': '中'},...
STUDENT_DICT = {
1: {'name': 'Old', 'age': 38, 'gender': '中'},..
def
return render_template('index1.html', stu_info = STUDENT, stu_list = STUDENT_LIST, stu_dict = STUDENT_DICT,absum =ab)
3.2 模板文件写法
(1)stu_info
<table border="1px">
<tr>
<td>name</td>
<td>age</td>
<td>gender</td>
</tr>
<tr>
<td>{{ stu_info.name }}</td>
<td>{{ stu_info.get('age') }}</td>
<td>{{ stu_info['gender'] }}</td>
#三种方式都可以获得字典的 但是key的慎用
(2)stu_list
{% for foo in stu_list %} #(改性别)
<td>{% if foo.gender!='男' and foo.gender!='女' %}
女
{% else %}
{{ foo.gender }}
(3)stu_dict(两种方式 dict或者items()(不要忘了括号))
{% for id in stu_dict %}
<tr>
<td>{{ id }}</td>
<td>{{ stu_dict[id].name }}</td>
<td>{{ stu_dict.get(id).get('age') }}</td>
{% for id,s in stu_dict.items() %}
<tr>
<td>{{ id }}</td>
<td>{{ s.name }}</td>
<td>{{ s.get('age') }}</td>
id 和 s
{# {{ id }} {#1 {'name': 'Old', 'age': 38, 'gender': '中'} 2 {'name': 'Boy', 'age': 73, 'gender': '男'} 3 {'name': 'EDU', 'age': 84, 'gender': '女'}#} #}
{# {{ s }}#}
(4)所有的模板都用到这个函数(传函数)
@app.template_global() #全局的
def ab(a,b):
return a+b
通常做一个模块,到引入就行了,都引入
return render_template('index1.html',absum =ab)#传到模板 #不用absum的 全局的
模板使用
center>{{ absum }}</center>
<center>{{ ab(2,2) }}</center>
#<function ab at 0x0000000003873488>
#4
(5)宏函数(什么用?)生成一个标签?
{% macro my_input(na,ty)%}
<input type="{{ ty }}" name="{{ na }}">
{% endmacro %}
{{ my_input('uname','text')}}
传给模板一个标签
my_in = Markup("<input type= 'text',name='uname'>")
return render_template('index1.html',m=my_in)
{{m}} #使用
3.2 jinja2
{{}} 引用 or 执行
{%%} 逻辑语法 if for else
今天上课都是因为一个,逗号困住,所以不得往下面的,可惜,细节
4 session
登录页面提交方式
<h1>login</h1>
{#<form action="/login?id=1&ids=2" method="post" enctype="multipart/form-data">#}
#url却是post方式的提交
<form action="" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="pwd">
{# <input type="file" name="my_file">#} #提交文件
<input type="submit" value="登录">
session和request同级的,不和Django一样,request.django
request = LocalProxy(partial(_lookup_req_object, "request"))
session = LocalProxy(partial(_lookup_req_object, "session")) #基本一样
登录+加入session(默认31天)
app.secret_key = '*Ud8fadjfadkjfaidjf' #验证码
@app.route('/login',methods=['POST',"GET"])
def login():
if request.method == 'GET':
return render_template('login.html')
uname = request.form.get('username')
pwd = request.form.get('pwd')
if uname == '123' and pwd == '123':
session['username'] = uname
session登录
@app.route('/detail')
def detail():
if session.get('username'):
return render_template('index.html')
else:
return redirect('/login')
session存到哪了?
Flask中的Session 不是三方组件 //Flask-Session
- 内置的
from flask import session
session['username'] = uname #加入session
RuntimeError
The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
解决: app.secret_key = '*Ud8fadjfadkjfaidjf' ####密钥的写法不是app.session,而是app
session 交由客户端保管
反序列化机制
当客户端发起请求 -request 带上cookie - cookie中有session的加密字符串 -flask 收到session加密字符串 - 通过 secret_key 解密session的加密字符串 获得 {username : 123}
app.permanent_session_lifetime = 15 (默认是秒)
都可以改 这些内容 (别再源码里改,提出来改)进入源码: session-->global session app.py里的内容
"PERMANENT_SESSION_LIFETIME": timedelta(days=31),
程序里改:
app.permanent_session_lifetime = 15
查看在前端application-->Cookies--> 代替了cookie, network点击login里没有改
app.session_cookie_name = "I am Not Session"
app.testing = True
序列化机制
开启session - session['username'] = uname
创建一个字典 {username:123} 接下来 通过secret_key(密钥安全) + 时间戳 + 签名 加密 形成
eyJ1c2VybmFtZSI6IjEyMyJ9.XSVovw.g6ZxiiEw_0EhRHF--oTG9Ac-ZF8 session的加密字符串
签名.时间戳.数据
if uname == '123' and pwd == '123':
session['username'] = uname
if uname == '123' and pwd == '123':
session['username'] = uname
session['username1'] = uname
session['username2'] = uname
.eJyrViotTi3KS8xNVbJSMjQyVtKBCxhiiBhhiBhDRWoBGaYU8w.XSXASw.cExXNorpTmERznwqRl9mdO4Tu7Y 写了多个session,session就多了很多 因为{username:123,username1:123,} 有公共机制所以说: 不会太长了
if uname == '123' and pwd == '123':
session['dasgas'] = '打分'
session['ada'] = '网页'
.eJyrViotTi3KS8xNVbJSiik1NTK0iCk1SzFIUtKByxjiljLCLWWMLlULACpUIRM.XSXBYw.uZrsOt2eoTJX4pJPoxQk4wSxjJY(多了,因为2个汉字6个)
不能线上开debug,会暴露密钥,在前端页面显示错误的时候,可能就会暴露,相对安全不是绝对的安全了
5 全局变量global
错了好多次了
a = 0
@app.route('/detail')
def detail():
global a
if session['username']:
a += 1
print(a)
作业:
1 用装饰器装饰一个登录函数
返回request(双重装饰器)
2 每一个视图函数都加上装饰器
能写三遍的不写两遍,背诵默写,哪不会的
工具:
不要太依赖,如果没有pycharm怎么办
记事本怎么写,能不能写 (今天学的可不可以写)
之后可能是各种工具
之后花钱买个 视频 看看破解版的 专业的(两三块钱)
不要更新 (把算法替换掉)
pycharm 是java写的, java的算法 , 乱码是算法的值,就连上了
规划:技术之上
技术:是掉接口的码农?还是
架构:更偏向技术
懂技术的产品还可以
工作经验
会,必须要全会,才算掌握一个语言 --龙
面试
看面试官 眉心 就可以把人看紧张了
吹了27k,本来15k。。。压力也大
15 16 K的程序员 都是应用层次的 用过什么
25k的左右的是接触过什么架构 什么项目
吹得话: ai开放能力,找一个,学或者了解()
人工智能 有标签 ,提上简历,有一个算法,招标签
龙交的nlp,还真会点 18k,把自己吹太牛了,不敢去(很能吹的南方人 能吹offer多7个)
遇到特别不屑的,直接走,转身走(不要回头)
sanic
学习稍微难些
最新的框架,python最快的 (先天写的东西都比他快的很多)(世界上没有最好的语言,自己用的就是最好的,没有最好的程序员,自己) python数据计算非常快
错误1 多加了个逗号字典变元祖
STUDENT = {'name': 'Old', 'age': 38, 'gender': '中'} ,
stu_info = STUDENT 时 , stu_info.name 等都没有值,是空的 ,而stu_info 有值 等于:
({'name': 'Old', 'age': 38, 'gender': '中'},)
以后不要犯这种错误
多加了个,成了元祖类型了(其实提示了tuple not get ,但是不看提示,看了也不懂把)
自己写程序出的错
错误2 AttributeError
1 AttributeError: read only property
request.method = ['POST','GET'] --->request.methods = ['POST','GET']
2 jinja2.exceptions.TemplateNotFound
jinja2.exceptions.TemplateNotFound: login.html #---> 扔到主目录下,把文件
3 Method Not Allowed (405 403)
The method is not allowed for the requested URL.
request.methods = ['POST','GET'] #这个写法不对,没法分配POST方法
-->@app.route('/login',methods=['POST',"GET"])#直接写上面
错误3 记错命令 还一直坚持尝试
ctrl + enter 不是快速导入的命令
alt + enter 才是快速导入模块的命令
快捷键1
再加个命令 ctrl+shift+i 是前端的检查快捷键