欢迎来到十九分快乐的博客

生死看淡,不服就干。

1.Anaconda虚拟环境创建 - Flask安装-路由-请求响应

Flask 基础

简介:

Flask 本身相当于一个内核,其他几乎所有的功能都要用到扩展,其 WSGI 工具箱采用 Werkzeug(路由模块),模板引擎则使用 Jinja2。这两个也是 Flask 框架的核心。

官网: https://flask.palletsprojects.com/en/1.1.x/

官方文档: [http://docs.jinkan.org/docs/flask/](

Flask常用第三方扩展包:

  • Flask-SQLalchemy:操作数据库,ORM;
  • Flask-script:终端脚本工具,脚手架;
  • Flask-migrate:管理迁移数据库;
  • Flask-Session:Session存储方式指定;
  • Flask-WTF:表单;
  • Flask-Mail:邮件;
  • Flask-Bable:提供国际化和本地化支持,翻译;
  • Flask-Login:认证用户状态;
  • Flask-OpenID:认证, OAuth;
  • Flask-RESTful:开发REST API的工具;
  • Flask JSON-RPC: 开发rpc远程服务[过程]调用
  • Flask-Bootstrap:集成前端Twitter Bootstrap框架
  • Flask-Moment:本地化日期和时间
  • Flask-Admin:简单而可扩展的管理接口的框架

可以通过 https://pypi.org/search/?c=Framework+%3A%3A+Flask 查看更多flask官方推荐的扩展

1.创建flask项目

创建虚拟环境

Anaconda3.x 安装

官方地址:https://www.anaconda.com/products/individual

页面最下方找到Linux版本,选择第一个下载。下载完成以后打开终端,执行命令:

bash Anaconda3-2020.11-Linux-x86_64.sh

一路回车,再输入yes

这里是询问anaconda的安装保存位置,默认是当前用户家目录下。将来anaconda

的所有虚拟环境都在这个目录下的envs目录下。

安装完成了。接下来,验证下是否安装成功了。关闭当前终端,打开一个新的

终端,命名行左边出现 (base) ,而且输入python3回车出现Anaconda则表示安装

并可以正常使用了。base是Anaconda自带的全局环境。

Anaconda基本操作

# 查看conda版本号
conda -V

# 1.查看当前Anaconda的系统配置信息 
conda info 
# 2.列出当前系统中所有虚拟环境
conda env list
# 3.创建虚拟环境 
conda create -n <虚拟环境名称> python=<python版本号> <包名1>==<版本 号> <包名2> ... 

-- 创建new虚拟环境,指定各种软件版本,如果服务器没有,创建虚拟环境会自动下载,不需要再手动添加了
conda create -n new python=3.8.5 django==2.2

# 4.克隆虚拟环境
conda create -n <新的虚拟环境名称> --clone <旧的虚拟环境名称>

# 5.进入/切换到指定名称的虚拟环境,如果不带任何参数,则默认回到全局环境base 中。
conda activate <虚拟环境名称>

# 6.退出当前虚拟环境 
conda deactivate

# 7.删除指定虚拟环境
conda remove -n <虚拟环境名称> --all

# 8.导出当前虚拟环境的Anaconda包信息到环境配置文件environment.yaml中
conda env export > environment.yaml

# 9.根据环境配置文件environment.yaml的包信息来创建新的虚拟环境
conda env create -f environment.yaml

部署/迁移

### 以下命令,和Anaconda没半毛钱关系,和项目部署/迁移有关。

pip freeze # 这里列出的是我们手动安装的包
pip list # 这里列出的不仅有我们手动安装的包,还有虚拟环境运行的依赖包

# 导出当前虚拟环境中的所有包并记录到requirements.txt文件中
pip freeze > requirements.txt
pip list --format=freeze > requirements.txt

# 往当前虚拟环境中导入requirements.txt文件中记录的所有包。
pip install -r requirements.txt

创建flask项目

# 1.创建flask虚拟环境
conda create -n flask python=3.8.5

# 2.安装flask
pip install flask==1.1.4

# 3.创建项目
创建项目目录 flaskdemo,在目录中创建manage.py.在pycharm中打开项目并指定上面创建的虚拟环境

创建一个flask框架的主程序。名字可以是app.py/run.py/main.py/index.py/manage.py

manage.py

# 导入Flask类
from flask import Flask

# 初始化
"""
import_name      Flask程序所在的包(模块),传 __name__ 就可以
                 其可以决定 Flask 在访问静态文件时查找的路径
static_path      静态文件访问路径(不推荐使用,使用 static_url_path 代替)
static_url_path  静态文件访问路径,可以不传,默认为:/ + static_folder
static_folder    静态文件存储的文件夹,可以不传,默认为 static
template_folder  模板文件存储的文件夹,可以不传,默认为 templates
"""
app = Flask(__name__)

# 编写路由视图
# flask的视图函数,flask中默认允许通过return返回html格式数据给客户端
@app.route('/')
def index():
    return 'hello <h1>world!!</h1>'

if __name__ == '__main__':
    # 运行flask,IP和端口,进入调试模式
    app.run(host='0.0.0.0',port=5000,debug=True)

2.路由的基本定义

什么是路由?

路由就是一种映射关系。是绑定应用程序和url地址的一种一对一的映射关系!我们在开发过程中,编写项目时所使用的路由往往是指代了框架/项目中用于完成路由功能的类,这个类一般就是路由类,简称路由。

url中可以传递路由参数:两种方式

1.任意路由参数接收

# 参数传递,没有限定类型
@app.route('/<user_id>')
def index(user_id):
    return 'hello %s'% user_id

2.限定路由参数接收

限定路由参数的类型,flask系统自带转换器编写在werkzeug.routing.py文件中

转换器名称 描述
string 默认类型,接受不带斜杠的任何文本
int 接受正整数
float 接受正浮点值
path 接收string但也接受斜线
uuid 接受UUID(通用唯一识别码)字符串 xxxx-xxxx-xxxxx-xxxxx
# flask提供了路由转换器可以让我们对路由参数进行限定
# 路由传递参数[限定数据类型]
@app.route('/user/<int:user_id>')
def user_info(user_id):
    return 'hello %d' % user_id

# 限定参数值范围
@app.route('/user/<int(min=10,max=100):user_id>')
def user_info(user_id):
    return 'hello %d' % user_id 

自定义路由参数转换器

也叫正则匹配路由参数.

# 1.引入flask内置的路由转换器父类
from werkzeug.routing import BaseConverter

# 2.创建自定义路由转换器,继承父类
class RegexConverter(BaseConverter):
    def __init__(self,map,*args):
        super().__init__(map)
        # self.regex = args[0]
        self.regex = "1[3-9]\d{9}"
        
# 3.把自定义转换器添加到flask默认的转换器字典中,名称为re,也就是和原来的int,float等放在一块
app.url_map.converters['re'] = RegexConverter

# 4.调用自定义转换器名称
# @app.route(rule='/user/<re("1[3-9]\d{9}"):phone>')
@app.route(rule='/user/<re:phone>')
def user(phone):
    print(app.url_map)
    return phone

路由限定请求方式

from flask import Flask,request

@app.route('/<int:user_id>',methods=["post","put","get","delete","patch"])
def index(user_id):
    print(request.method) # 获取本次客户端的http请求方法         
    print(request.query_string)  # 获取本次客户端的查询字符串    
    print(request.path)  # 获取本次客户端请求的路由路径部分[去掉域名端口]    
    print(request.url) # 获取本次客户端请求的http url地址   
    return 'hello %s'% user_id

# 例如,post请求, http://127.0.0.1:5000/4378?username=jyh
POST
b'username=jyh'
/4378
http://127.0.0.1:5000/4378?username=jyh

3.http的请求与响应

请求 - request

常用的属性如下:

属性 说明 类型
data 记录请求体的数据,并转换为字符串
只要是通过其他属性无法识别转换的请求体数据,最终都是保留到data属性中
例如:有些公司开发小程序,原生IOS或者安卓,这一类客户端有时候发送过来的数据就不一样是普通的表单,查询字符串或ajax
bytes类型
form 记录请求中的html表单数据 MultiDict
args 记录请求中的查询字符串,也可以是query_string MultiDict
cookies 记录请求中的cookie信息 Dict
headers 记录请求中的请求头 EnvironHeaders
method 记录请求使用的HTTP方法 GET/POST
url 记录请求的URL地址 string
files 记录请求上传的文件列表 *
json 记录ajax请求的json数据 json

获取请求中各项数据

from flask import Flask,request
from urllib.parse import parse_qs

# 初始化
app = Flask(__name__)

# 获取查询字符串
@app.route('/')
def index():
    print(request.query_string) # 获取原生查询参数 username=jyh&pwd=123&pwd=abc
    print( parse_qs( request.query_string.decode() ) ) # 解析
    
    print(request.args) # 获取解析后的查询字符串
    """
    请求地址:127.0.0.1:5000/?username=jyh&pwd=123&pwd=abc
    打印效果:ImmutableMultiDict([('username', 'jyh'), ('pwd', '123'), ('pwd', 'abc')])
    字典本身不支持同名键的,ImmutableMultiDict类解决了键同名问题
    """
    # 获取指定的查询参数
    print(request.args['username']) #jyh
    print(request.args.get('username')) #jyh
    print(request.args.getlist('pwd')) #['123', 'abc'] 参数同名的都能列出来

    # 获取字典类型查询参数
    print(request.args.to_dict(flat=True)) # {'username': 'jyh', 'pwd': '123'}
    print(request.args.to_dict(flat=False)) # {'username': ['jyh'], 'pwd': ['123', 'abc']}
    
    
    return 'hello world!'

# 获取请求数据
@app.route(rule='/data',methods=['post','put','patch'])
def data():
    # 1.获取请求体数据,是其他属性无法接收到的数据
    print(request.data)
    
    # 2.获取form表单数据
    print(request.form) # 元组类型
    print(request.form.get('name'))
    
    # 3.获取json数据 - ajax上传的数据或其他json数据
    print(request.json)
    print(request.json.get('name'))
    
    # 4.获取file文件数据
    print(request.files) # ImmutableMultiDict([('avatar', <FileStorage: '1.webp' ('image/webp')>)])
    print(request.files['avatar']) # <FileStorage: '1.webp' ('image/webp')>
    print(request.files.get('avatar')) # <FileStorage: '1.webp' ('image/webp')>

    # 5.获取请求头信息
    print(request.headers)
    print(request.headers.get('Host')) # 127.0.0.1:5000
    """
        请求头信息
        Content-Type: application/json
        User-Agent: PostmanRuntime/7.26.10
        Accept: */*
        Postman-Token: 37e819e7-38db-4b47-b5ab-059cfaffd2d4
        Host: 127.0.0.1:5000
        Accept-Encoding: gzip, deflate, br
        Connection: keep-alive
        Content-Length: 20
    """
    # 6.获取请求的URL地址
    print(request.url) # http://127.0.0.1:5000/data
    print(request.path) # /data
	print(request.remote_addr) # IP地址 127.0.0.1
    
    return 'ok'

# 声明和加载配置 - 开启调试模式
class Config():
    DEBUG = True
app.config.from_object(Config)

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5000)

响应

flask默认支持两种响应方式:

# 1.数据响应 - make_response  jsonify
默认响应html文本,也可以返回 JSON格式,或其他格式

# 2.页面响应: 重定向 - redirect
	url_for: 视图之间的跳转,获取视图对应的url地址,在使用redirect跳转页面
	
# 3.响应的时候,flask也支持自定义http响应状态码

响应各种数据

from flask import Flask,request,make_response,redirect,jsonify,url_for

# 初始化
app = Flask(__name__)

# 1.响应html文本数据 - make_response
@app.route(rule='/')
def index():
    # 默认支持响应HTML文本
    # return '<a href="https://www.baidu.com/">跳转百度</a>'
    return make_response('<a href="https://www.baidu.com/">跳转百度</a>')

# 2.响应json数据 - jsonify
@app.route(rule='/json')
def json():
    data = [
        {"name":"jyh","age":11},
        {"name":"sxy","age":12},
        {"name":"gzs","age":13},
    ]
    # flask中返回json 数据,都是flask的jsonify方法返回就可以了
    return jsonify(data)


# 3.响应自定义格式数据 - 必须定义响应类型
'''响应图片类型数据'''
@app.route(rule='/image')
def image():
    with open('1.webp','rb')as fp:
        content = fp.read()
    response = make_response(content)
    response.headers['content-type'] = 'image' #定义响应类型 MIME type 其他类型网上搜
    return response

# 4.重定向
'''4.1重定向到百度页面或自己页面 - 路径'''
@app.route(rule='/bai')
def dai():
    # return redirect('https://www.baidu.com/')
    return redirect('/json')

'''
    4.2重定向到自己写的json数据页面
    使用url_for可以实现视图方法之间的内部跳转
    url_for("视图方法名")
    仅仅是根据参数从app.url_map中提取对应函数的url地址
'''
@app.route(rule='/gojson')
def gojson():
    url = url_for('json')
    print(url) # /json
    return redirect(url)

'''4.3重定向到带有参数的视图函数'''
@app.route(rule='/user/<user_id>')
def user(user_id):
    return f'user_id = {user_id}'

@app.route(rule='/gouser')
def gouser():
    # return redirect(url_for(endpoint='user',user_id=123))
    return redirect(url_for('user',user_id=123))


# 5.自定义状态码和响应头
'''自定义状态码'''
@app.route(rule='/status')
def status():
    return 'status = 666',400

'''自定义状态码和响应头'''
@app.route(rule='/respon')
def respon():
    response = make_response('ok')
    print(response) # <Response 2 bytes [200 OK]>
    response.headers['Hehe'] = '666' # 自定义响应头
    response.status_code = 201 # 自定义响应状态码

    return response


# 声明和加载配置 - 开启调试模式
class Config():
    DEBUG = True
app.config.from_object(Config)

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5000)

4.http会话控制

所谓的会话,就是客户端浏览器和服务端网站之间一次完整的交互过程.

会话的开始是在用户通过浏览器第一次访问服务端网站开始.

会话的结束时在用户通过关闭浏览器以后,与服务端断开.

所谓的会话控制,就是在客户端浏览器和服务端网站之间,进行多次http请求响应之间,记录、跟踪和识别用户的信息而已。

因为 http 是一种无状态协议,浏览器请求服务器是无状态的。

无状态:指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。

无状态原因:浏览器与服务器是使用 socket 套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的 socket 连接,而且服务器也会在处理页面完毕之后销毁页面对象。

有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等

实现状态保持主要有两种方式:

  • 在客户端存储信息使用Cookie,token[jwt,oauth]
  • 在服务器端存储信息使用Session
补充:
token是一种用户身份认证信息的技术,一般我们称之为:Token认证。
翻译中文:token一般叫令牌
本质就是一个经过特殊处理的字符串,往往在字符串内部隐藏着识别用户身份信息的关键内容。
一般开发中,token往往都是以识别用户身份为目的来使用的。

一般使用情况下,token会以用户身份信息,当前事件戳,随机数等因子构成的。
当然,更多情况下,token一般分三段:"头部.载荷.签证"
像实际开发中,我们一般说的jwt,csrf等等场景里面的token都是这一类的。

Cookie是由服务器端生成,发送给客户端浏览器,浏览器会自动将Cookie的key/value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie的key/value可以由服务器端自己定义。

使用场景: 登录状态, 浏览历史, 网站足迹, 购物车 [不登录也可以使用购物车]

Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用

Cookie基于域名安全,不同域名的Cookie是不能互相访问的

浏览器的同源策略针对cookie也有限制作用.

当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器,所以在request中可以读取Cookie信息

session

对于敏感、重要的信息,建议要存储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息

在服务器端进行状态保持的方案就是Session

Session依赖于Cookie,session的ID一般默认通过cookie来保存到客户端。

设置/获取cookie - 设置/获取session

from flask import Flask,request,make_response,session

# 初始化
app = Flask(__name__)

# 1.设置cookie - 通过response响应对象设置
@app.route(rule='/set_cookie')
def set_cookie():
    response = make_response('set cookie')
    response.set_cookie('username','jyh') # 过期时间是会话期,关闭浏览器以后,自动删除
    # response.set_cookie('username','jyh',max_age=3600) # 在指定max_age时间以后,才会自动删除
    response.set_cookie('username','jyh',3600)
    return response

# 2.获取cookie - 通过request获取
@app.route(rule='/get_cookie')
def get_cookie():
    res = request.cookies.get('username')
    return res

# 3.删除cookie - 通过设置cookie过期时间,让浏览器删除cookie
@app.route(rule='/delete_cookie')
def delete_cookie():
    response = make_response()
    # response.set_cookie('username','',max_age=0) # 0或负数 代表过期
    response.set_cookie('username','',0)
    return response


# 4.设置session
# 加载配置 - 使用session之前必须配置SECRET_KEY秘钥,否则报错,秘钥是随机字符串
class Config():
    DEBUG = True
    SECRET_KEY = "jyh123"
app.config.from_object(Config)

@app.route(rule='/set_session')
def set_session():
    session['username'] = 'jyh'
    return 'set_session'

# 5.获取session
@app.route(rule='/get_session')
def get_session():
    return session.get('username')

# 6.删除session
@app.route(rule='/del_session')
def del_session():
    # 先判断是否有session值,再删除,否则报错
    if session.get('username'):
        def session['username']
    return 'del_session'

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5000)

posted @ 2021-05-21 19:21  十九分快乐  阅读(1229)  评论(0编辑  收藏  举报