flask基础之一

发布时间:2019-09-26 07:19:58编辑:auto阅读(1677)

    flask基础之一

    hello world

    #从flask这个包中导入Flask这个类
    #Flask这个类是项目的核心,以后的很多操作都是基于这个类的对象
    #注册url,注册蓝图都是这个类的对象
    from flask import Flask
    #创建一个Flask对象,传递__name__这个参数进去
    #__name__这个参数的作用:
    # 1.规定模板和静态资源的路径
    # 2.以后的一些Flask插件,比如Flask_migrate,Flask_SQLAlchemy报错的话,哪么Flask就会通过这个参数找到具体的报错位置
    app = Flask(__name__)
    # @app.route()是一个装饰器,将对应的“/”路径应用到hello_world()这个函数上面
    # 在访问“/”的时候在页面上返回Hello World
    @app.route('/')
    def hello_world():
        return 'Hello World!'
    # 如果作为一个主文件运行,哪么执行app.run()方法,也就是启动这个网站
    if __name__ == '__main__':
        app.run()

    debug模式

    • 为什么要开启DEBUG模式?
    • 如果开启了debug模式,name代码在调试过程中出现了异常,在浏览器页面中可以看到具体的报错信息,以及具体的错误代码位置,方便开发者调试。
    • 如果flask开启了debug模式,name以后再python中修改任何代码,只要在pycharm中使用ctrl+s即可保存重载,不需要手动去重载程序
    • 如何配置debug模式:

    app.run()

    app.run(debug=True)

    app.debug

    app.debug = True

    配置信息方式(使用参数形式的方式)

    app.config.update[DEBUG=True]
    #其实也就是update了config字典

    通过配置文件的形式

    - 创建一个config.py的配置文件,写入
    DEBUG = True
    - 然后在你的app.py文件中写入
    app.config.from_object(config) #即可读取配置文件中的DEBUG=True

    debug PIN码

    D:\MyDevSoftInstallDir\Python3\python3.exe D:/myflask/base/base.py
    * Restarting with stat
    * Debugger is active!
    * Debugger PIN: 177-952-649
    * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

    然后在页面上调试代码的时候用到。
    也是为了安全考虑。

    配置文件两种方式详解

    • 第一种方式:

    在项目主路径下创建config.py

    DEBUG=True

    然后在主项目里面去读取config.py里面的配置:

    from flask import Flask
    import config
    app = Flask(__name__)
    app.config.from_object(config)
    • 第二种方式:直接读取文件的形式,也可以是普通的txt文件形式;这种方式不需要直接import config

    在项目主路径下创建config.py

    DEBUG=True

    然后在主项目里面去读取config.py里面的配置:

    from flask import Flask
    app = Flask(__name__)
    app.config.from_pyfile('config.py',silent=True) #静默模式加载配置文件(找不到配置文件不报错),文件的后缀名不可少

    url与视图函数的映射

    • 传递参数:
    传递参数的语法是/<参数类型:参数名称>/,然后在视图函数中也要定义同名的参数
    • 参数的数据类型
    • string:只接受字符串,没有任何“/或者”的文本
    • int:只接受整数
    • float:只接受浮点数,整数都不行哈
    • path:和string类似,但是接受斜杠
    • uuid:只有接受符合uuid的字符赤岸,一般用作表的主键
    • any:可以指定多种路径

    接收用户传递参数的方式:

    • 使用path的方式(将参数嵌入到路径中)
    • 使用查询字符串的形式 (也就是通过?key=value的形式传递的,只能通过request.args.get的方式来获取)

    如果页面想要做SEO优化的话,那么推荐使用path的形式,反之就是查询字符串的形式
    练习

    from flask import Flask,request
    app = Flask(__name__)
    @app.route('/')
    def hello_world():
        return 'Hello World!'
    @app.route('/list/')
    def article_list():
        return 'article list!'
    @app.route('/p1/<article_id1>')
    def article_detail(article_id1):
        return "请求的文章是:%s" %article_id1
    @app.route('/p2/<string:article_id2>')
    def article_detail2(article_id2):
        return "请求的文章是:%s" %article_id2
    @app.route('/p3/<int:article_id3>')
    def article_detail3(article_id3):
        return "请求的文章是:%s" %article_id3
    @app.route('/p4/<path:article_id4>')
    def article_detail4(article_id4):
        return "请求的文章是:%s" %article_id4
    # import uuid
    # print(uuid.uuid4())
    @app.route('/p5/<uuid:article_id5>') #数据的唯一性,长度较长,有损效率(一般在用户表中使用)6a9221f6-afea-424a-a324-8ceaa5bdfc98
    def article_detail5(article_id5):
        return "请求的文章是:%s" %article_id5
    @app.route('/p6/<any(blog,user):url_path>/<id>/')
    def detail(url_path,id):
        if url_path == "blog":
            return "博客详情 %s" %id
        else:
            return "用户详情 %s" %id
    #通过问号形式传递参数
    @app.route('/d/')
    def d():
        wd = request.args.get('wd') #获取浏览器传递参数
        return '通过查询字符串的方式传递的参数是,%s'%wd #请求http://127.0.0.1:8080/d/?wd=php
    if __name__ == '__main__':
        app.run(debug=True,host='0.0.0.0',port=8080)

    url_for

    • 将视图函数反转回URL,跟app.route相反
    • URL的更新大于视图函数,所以在大规模项目中比较实用

    * 基本使用

    • url_for的第一个参数是视图函数的函数名对应的字符串(endpoint),后面的参数就是你传递给url;如果传递的参数在url中已经定义了,那么这个参数就会被当成path的值传递给url;如果这个参数没有在url中定义,那么将变成查询字符串的形式
    from flask import Flask,url_for,request
    app.route('/')
        return url_for('my_list',page=1,count=2) #这样的话就会在页面上构建出/post/list/1/?count=2的信息
    app.route('/post/list/<page>/')
    def my_list():
        return 'my list'
    • 为什么需要url_for
    如果将来要修改URL,但没有修改URL对应的函数名,就不用到处去替换URL了。
    URL会自动处理特殊字符(转义成十六进制),不需要手动去处理
    from flask import Flask,url_for,request
    @app.route('/')
    def hello_world():
        return url_for('login',next='/current') #页面返回/login/?next=%2Fcurrent登录前的信息
        # print(url_for('my_list',page=1,count=200))
        # return 'hello world'
    @app.route('/login/')
    def login():
        # next = request.args.get('next') #登录前的信息,在登陆之后仍旧保持
        return 'login'
    @app.route('/list/<page>')
    def my_list():
        return 'my list'
    @app.route('/detail/<id>/')
    def detail():
        return 'detail'
    if __name__ == '__main__':
        app.run(debug=True)

    自定义url转换器

    • url的参数转换成满足自己需求的数据类型

    自定义url转换器的方式:

    1. 实现一个类,继承BaseConverter
    1. 在自定义的类中重写regex,也就是这个变量的正则表达式
    2. 将自定义的类映射到app.url_map.converters上。

    实现用户访问/posts/a+b
    to_python的作用
    这个方法的返回值会传到view函数中作为参数
    to_url的作用
    这个方法的返回值会调用url_for来生成符合要求的url形式

    from flask import Flask,url_for
    from werkzeug.routing import BaseConverter
    app = Flask(__name__)
    #手机号码正则
    class TelephoneConveter(BaseConverter):
        regex = r'1[85734]\d{9}'
    app.url_map.converters['tel'] = TelephoneConveter
    #用户访问/posts/a+b/
    class ListConverter(BaseConverter):
        def to_python(self, value):
            return value.split("+")
        def to_url(self, value):
            print(value)
            return '+'.join(value)
            # return "hello"
    app.url_map.converters['list'] = ListConverter
    @app.route('/')
    def hello_world():
        print(url_for('posts',broads=['a','b']))
        return 'Hello World!'
    @app.route('/user/<int:user_id>/')
    def user(user_id):
        return "your user id is %d" %user_id
    @app.route('/telephone/<tel:my_tel>/')
    def my_tel(my_tel):
        return "your telephone number is %s"%my_tel
    @app.route('/posts/<list:broads>/')
    def posts(broads):
        # broads = broads.split("+")
        return "your posts is %s"%broads
    if __name__ == '__main__':
        app.run(debug=True)

    小细节

    在局域网访问站点

    app.run(host='0.0.0.0')

    指定端口号

    默认是5000端口,修改端口如下

    app.run(host='0.0.0.0',port=8899 )

    ulr唯一

    • 在定义URL的时候,尽量在url后面加/,原因如下:

      • 如果不加/的话浏览器访问这个url的时候会默认加/,这样的话就访问不到了
      • 搜索引擎会将不加/的url和加/的url是两个不同的url,会将其误解。

    GET和POST请求

    在网络请求中有许多的请求方式,比如GET,POST,DELETE,PUT,常用的请求方式如下:

    • GET:也就是获取服务器上的资源,不会修改服务器上的内容。
    • POST:就是向服务器提交文件或者数据,一般POST会对服务器的状态产生影响。
    • 关于参数传递:

      • GET:把参数放到URL中,通过?xx=xxx的形式传递的,因为会把参数放到url中,所以视力好的话,一眼就可以看到传递的参数。
      • POST:把参数放到Form Data中,避免被偷窥到的风险(也有可能通过抓包的方式被窃取),一般不安全的,不晓得提交的内容是否是带病毒的文件。
    flask中,route方法,默认只能使用GET的方式请求url。如果想要设置自己的请求方式,那就要在methods中多传递一个请求方式的参数。
    实例如下:
    创建url_detail的项目,项目结构如下:
    ├─url_detail.py
    ├─static
    └─templates
       |_login.html
    • url_detail.py"
    from flask import Flask,request,render_template
    app = Flask(__name__)
    @app.route('/',methods=['GET'])
    def hello_world():
        return 'Hello World!'
    @app.route('/list/',methods=['POST'])
    def my_list():
        return 'list'
    @app.route('/login/',methods=["POST","GET"])
    def login():
        if request.method == 'GET':
           return render_template('login.html')
        else:
            return "Success"
    if __name__ == '__main__':
        app.run(debug=True,host='0.0.0.0')
    • templates/login.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="",method="POST">
        <input type="text",name="username">
        <input type="text",name="password">
        <input type="submit",name="submmit">
    </form>
    </body>
    </html>

    URL重定向

    也就是从一个页面跳转到另一个页面,也就是重新定位一个方向
    分类:

    • 永久性重定向:http的状态码是301,多用于旧的网址废弃了要转到一个新的网址,确保用户的访问。最经典的就是jingdong.com
    • 暂时性重定向:http的状态码是302,表示页面暂时性被跳转,比如访问一个需要权限的网址,如果当前用户没有登录,应该重定向到登录页面。这种情况的话就是用暂时性重定向。
    在flask中,重定向是通过flask.redirect(location,code=302)这个函数来实现的,location指的是需要重定向到的URL,应该配合之前讲过的url_for()来是用。code代表的是什么类型的重定向,默认是302,可以修改成301实现永久重定向。
    • 小例子:
    from flask import Flask,url_for,redirect,request
    app = Flask(__name__)
    app.debug = True
    @app.route('/login/',methods=['GET','POST'])
    def login():
        return 'login page'
    @app.route('/profile/',methods=['GET','POST'])
    def profile():
        name = request.args.get('name')
        if not name:
            return redirect(url_for('login'))
        else:
            return name
    if __name__ == '__main__':
        app.run()

    这样的话就能访问profile了:

    http://127.0.0.1:5000/profile/?name=sss

    关于响应

    视图函数的返回值会被自动转换成一个响应对象,flask的转换逻辑如下:

    • 如果返回的是一个合法的响应对象,则直接返回
    • 如果返回的是一个字符串,那么flask会重新创建一个werkzeug.wrappers.Response对象。Response会将该字符串作为主体,状态码为200,MIME的类型为text/html,然后返回给Response对象
    • 如果返回的是一个元组,元组中的数据类型是response,status,headers,status会覆盖默认的200状态码,headers可以是一个字典或者列表。作为额外的消息头
    • 如果以上的条件都不满足,flask会假设返回值是一个合法的WSGI应用程序,并通过Response.force_type(rv,request.environ)转换成一个请求对象。
    • 自定义响应

      • 必须继承自Response
      • 实现类方法:force_type
      • 必须指定app.response_class为你自定义的Response
      • 如果视图函数返回的数据既不是字符串,也不是元组,也不是Response对象,那么会将返回值传给force_type,然后将force_type的返回值返回给前端。
    #!/usr/bin/python
    # -*- coding:utf8 -*-
    from flask import Flask,Response,jsonify
    import json
    app = Flask(__name__)
    app.debug = True
    #自定义响应
    class JSONResponse(Response):
        @classmethod
        def force_type(cls, response, environ=None):
            '''
            这个方法只有视图函数返回非字符串,非元组,非Response对象才会调用
            :param response:
            :param environ:
            :return:
            '''
            print response
            print type(response)
            if isinstance(response,dict):
                #jsonify除了将字典转换成为json对象,还将对象封装成了一个Response对象
                response = jsonify(response)
                #response = json.dumps(response) #这样转换的话程序启动会报错
            return super(JSONResponse,cls).force_type(response,environ) #返回父类信息
    app.response_class = JSONResponse
    @app.route('/')
    #第一种情况
    def hello_world():
        #Response('Hello World',status=200,mimetype='text/html')
        return 'Hello World!'
    #第二种情况
    @app.route('/list1/')
    def list1():
        resp = Response('List1')
        resp.set_cookie('country','china')
        return resp
    #第三种情况
    @app.route('/list2')
    def list2():
        return 'list2',200,{'X-Name':'abc'}
    @app.route('/list3/')
    def list3():
        return {"username":"abc","age":11}
    if __name__ == '__main__':
        app.run(host='0.0.0.0')

关键字