zoukankan      html  css  js  c++  java
  • 1.Anaconda虚拟环境创建

    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)
    
    
  • 相关阅读:
    openssl之EVP系列之5---EVP_Encrypt系列函数具体解释(二)
    LINQ to SQL活学活用(1):这要打破旧观念
    【安卓】乾坤大罗移,将容器触摸事件传至还有一容器、!
    高速排序——JAVA实现(图文并茂)
    WebCollector爬取百度搜索引擎样例
    nyist 202 红黑树(二叉树中序遍历)
    excel转换日期格式,将yyyymmdd类型日期转换成yyyy-mm-dd等日期类型方法
    窗体界面设计03
    窗体界面设计02
    窗体界面设计01
  • 原文地址:https://www.cnblogs.com/jia-shu/p/14797146.html
Copyright © 2011-2022 走看看