• Flask 快速使用 —— (1)


     Flask、Django、Tornado框架 区别 

      1  Django:重武器,内部包含了非常多组件:ORM、Form、ModelForm、缓存、Session、中间件、信号等... 

      2   Flask:短小精悍,内部没有太多组件。第三方组件非常丰富。 路由比较特殊:基于装饰器来实现,但是究其本质还是通过add_url_rule来实现。

      3   Tornado:异步非阻塞框架 ,底层使用的是 IOLoop 使用协程实现的异步非阻塞

    wsji

     werkzeug示例

    from werkzeug.wrappers import Request, Response
    
    @Request.application
    def hello(request):
        return Response('Hello World!')
    
    if __name__ == '__main__':
        from werkzeug.serving import run_simple
        run_simple('localhost', 4000, hello)

    wsgiref示例

    from wsgiref.simple_server import make_server
     
    def runserver(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ]
     
     
    if __name__ == '__main__':
        # obj = WSGIHandler()
        httpd = make_server('', 8000, runserver)
        httpd.serve_forever()

     他们的本质都是基于sokect

    import socket
      
    def handle_request(client):
        buf = client.recv(1024)
        client.send("HTTP/1.1 200 OK
    
    ")
        client.send("Hello, Seven")
      
    def main():
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('localhost',8000))
        sock.listen(5)
      
        while True:
            connection, address = sock.accept()
            handle_request(connection)
            connection.close()
      
    if __name__ == '__main__':
        main()

    安装 Flask 

    pip3 install flask

     创建一个简单的Flask 程序

    from flask import Flask
    
    # 实例化Flask对象
    app = Flask(__name__)
    
    # 将 '/' 和 函数index的对应关系添加到路由中。
    """
    {
        ‘/’:index
    }
    """
    @app.route('/')
    def index():
        return 'Hello World!'
    
    
    if __name__ == '__main__':
        # 监听用户请求
        # 如果有用户请求到来,则执行app的__call__方法
        app.__call__
        app.run()

     

    通过写一个简单的登陆小案例来了解Flask的使用

    from flask import Flask,render_template,request,redirect,session,url_for
    app = Flask(__name__)
    app.debug = True
    app.secret_key = 'siuljskdjfs'
    
    USERS = {
        1:{'name':'张桂坤','age':18,'gender':'','text':"当眼泪掉下来的时候,是真的累了, 其实人生就是这样: 你有你的烦,我有我的难,人人都有无声的泪,人人都有难言的苦。 忘不了的昨天,忙不完的今天,想不到的明天,走不完的人生,过不完的坎坷,越不过的无奈,听不完的谎言,看不透的人心放不下的牵挂,经历不完的酸甜苦辣,这就是人生,这就是生活。"},
        2:{'name':'主城','age':28,'gender':'','text':"高中的时候有一个同学家里穷,每顿饭都是膜膜加点水,有时候吃点咸菜,我们六科老师每天下课都叫他去办公室回答问题背诵课文,然后说太晚啦一起吃个饭,后来他考上了人大,拿到通知书的时候给每个老师磕了一个头"},
        3:{'name':'服城','age':18,'gender':'','text':"高中的时候有一个同学家里穷,每顿饭都是膜膜加点水,有时候吃点咸菜,我们六科老师每天下课都叫他去办公室回答问题背诵课文,然后说太晚啦一起吃个饭,后来他考上了人大,拿到通知书的时候给每个老师磕了一个头"},
    }
    
    def wrap(func):
        def inner(*args, **kwargs):
            user = session.get('user_info')
            if not user:
                return redirect('/login')
            return func()
        return inner
    
    
    
    @app.route('/detail/<int:nid>',methods=['GET'],endpoint='n1') # 登陆后才能访问
    @wrap
    def detail(nid):
        info = USERS.get(nid)
        return render_template('detail.html',info=info)
    
    
    @app.route('/index',methods=['GET'],endpoint='n2') #  登陆后才能访问
    @wrap
    def index():
        user = session.get('user_info')
        print(user)
        if not user:
            # return redirect('/login')
            url = url_for('l1')
            return redirect(url)
        return render_template('index.html',user_dict=USERS)
    
    
    @app.route('/login',methods=['GET','POST'],endpoint='l1')
    def login():
        if request.method == "GET":
            return render_template('login.html')
        else:
            # request.query_string
            user = request.form.get('user')
            pwd = request.form.get('pwd')
            if user == 'zhang' and pwd == '123':
                session['user_info'] = user
                return redirect('http://www.baidu.com')
            return render_template('login.html',error='用户名或密码错误')
    
    if __name__ == '__main__':
        app.run()

    创建登陆模板  templates/login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>用户登录</h1>
        <form method="post">
            <input type="text" name="user">
            <input type="text" name="pwd">
            <input type="submit" value="登录">{{error}}
        </form>
    </body>
    </html>

    创建首页模板  templates/index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>用户列表</h1>
        <table>
            {% for k,v in user_dict.items() %}
            <tr>
                <td>{{k}}</td>
                <td>{{v.name}}</td>
                <td>{{v['name']}}</td>
                <td>{{v.get('name')}}</td>
                <td><a href="/detail/{{k}}">查看详细</a></td>
            </tr>
            {% endfor %}
        </table>
    </body>
    </html>

    创建详情页模板  templates/detail.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>详细信息 {{info.name}}</h1>
        <div>
    
            {{info.text}}
        </div>
    </body>
    </html>

     登陆设置session

    http://127.0.0.1:5000/login

     

    携带session 访问主页

    http://127.0.0.1:5000/index
    

    携带session 访问详情页

    http://127.0.0.1:5000/detail/1
    

    配置文件

    flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
        {
            'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式
            'TESTING':                              False,                          是否开启测试模式
            'PROPAGATE_EXCEPTIONS':                 None,                          
            'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
            'SECRET_KEY':                           None,
            'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
            'USE_X_SENDFILE':                       False,
            'LOGGER_NAME':                          None,
            'LOGGER_HANDLER_POLICY':               'always',
            'SERVER_NAME':                          None,
            'APPLICATION_ROOT':                     None,
            'SESSION_COOKIE_NAME':                  'session',
            'SESSION_COOKIE_DOMAIN':                None,
            'SESSION_COOKIE_PATH':                  None,
            'SESSION_COOKIE_HTTPONLY':              True,
            'SESSION_COOKIE_SECURE':                False,
            'SESSION_REFRESH_EACH_REQUEST':         True,
            'MAX_CONTENT_LENGTH':                   None,
            'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
            'TRAP_BAD_REQUEST_ERRORS':              False,
            'TRAP_HTTP_EXCEPTIONS':                 False,
            'EXPLAIN_TEMPLATE_LOADING':             False,
            'PREFERRED_URL_SCHEME':                 'http',
            'JSON_AS_ASCII':                        True,
            'JSON_SORT_KEYS':                       True,
            'JSONIFY_PRETTYPRINT_REGULAR':          True,
            'JSONIFY_MIMETYPE':                     'application/json',
            'TEMPLATES_AUTO_RELOAD':                None,
        }
     
    方式一:
        app.config['DEBUG'] = True
     
        PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...)
     
    方式二:
        app.config.from_pyfile("python文件名称")
            如:
                settings.py
                    DEBUG = True
     
                app.config.from_pyfile("settings.py")
     
        app.config.from_envvar("环境变量名称")
            环境变量的值为python文件名称名称,内部调用from_pyfile方法
     
     
        app.config.from_json("json文件名称")
            JSON文件名称,必须是json格式,因为内部会执行json.loads
     
        app.config.from_mapping({'DEBUG':True})
            字典格式
     
        app.config.from_object("python类或类的路径")
     
            app.config.from_object('pro_flask.settings.TestingConfig')
     
            settings.py
     
                class Config(object):
                    DEBUG = False
                    TESTING = False
                    DATABASE_URI = 'sqlite://:memory:'
     
                class ProductionConfig(Config):
                    DATABASE_URI = 'mysql://user@localhost/foo'
     
                class DevelopmentConfig(Config):
                    DEBUG = True
     
                class TestingConfig(Config):
                    TESTING = True
     
            PS: 从sys.path中已经存在路径开始写
         
     
        PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录
    

      

    在根目录下创建config.py

    class Config(object):
        DEBUG = False
        TESTING = False
        secret_key = "asdfasdf"
        DATABASE_URI = 'sqlite://:memory:'
    
    
    class ProductionConfig(Config):
        DATABASE_URI = 'mysql://user@localhost/foo'
    
    
    class DevelopmentConfig(Config):
        DEBUG = True

    创建s3.py ,引入配置文件 config.py

    from flask import Flask
    from config import DevelopmentConfig
    
    
    app = Flask(__name__)
    
    app.config.from_object(DevelopmentConfig)
    
    @app.route('/')
    def index():return 'Hello World!'
    
    
    if __name__ == '__main__':
        app.run()

    Flask 中路由的本质  

    1. decorator = app.route('/',methods=['GET','POST'],endpoint='n1')
        def route(self, rule, **options):
            # app对象
            # rule= /
            # options = {methods=['GET','POST'],endpoint='n1'}
            def decorator(f):
                endpoint = options.pop('endpoint', None)
                self.add_url_rule(rule, endpoint, f, **options)
                return f
            return decorator
    2. @decorator   ----> index = decorator(index)
        decorator(index)
    

      

    通过源码我们可以看到最终是通过  add_url_rule  添加路由的,基于这个我们可以模仿  

    from flask import Flask
    
    app = Flask(__name__)
    
    def login():
        return '登录'
    
    app.add_url_rule('/login', 'n2', login, methods=['GET',"POST"])
    
    
    if __name__ == '__main__':
        app.run(

     类视图

     之前使用的视图都是函数,简称为视图函数,视图也可以基于类来实现,类视图的好处是支持继承,类视图需要通过app.add_url_role(url_rule,view_func(name="必传的参数"))来进行注册,类里面要加装饰器就用:detactors=[]   ,里面可以添加多个装饰器

    可以设置类属性来做一些限制  methods 可以限制访问的请求方法  ,  decorators 增加装饰器 

    from flask import Flask,views
    
    app = Flask(__name__)
    app.debug = True
    app.secret_key = "asdfasdf"
    
    
    def auth(func):
        def inner(*args, **kwargs):
            result = func(*args, **kwargs)
            return result
        return inner
    
    class IndexView(views.MethodView):
        methods = ['GET'] # 只允许GET 请求访问
        decorators = [auth, ] # 添加装饰器
    
        def get(self):
            return 'Index.GET'
    
        def post(self):
            return 'Index.POST'
    
    app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint
    
    
    if __name__ == '__main__':
        app.run()

    add_url_rule中的参数介绍

    一个简单的重定向的小实例

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/index/',methods=['GET','POST'],endpoint='n1',redirect_to="/index2",)
    def index():return '公司老首页'
    
    
    @app.route('/index2/',methods=['GET','POST'],endpoint='n2',defaults={'nid':888},strict_slashes=True)
    def index2(nid):
        print(nid)
        return '公司新首页'
    
    if __name__ == '__main__':
        app.run()

     访问公司的内部网站有时需要修改hosts文件


    小工具:脚本 py文件【为公司测试人员开发的修改host文件的小程序】

      1 windows  C:WindowsSystem32driversetchosts 
      2 linux /etc/hosts
    添加以下的实例
    127.0.0.1:5000  www.baidu.com

    子域名访问

    在hosts文件中添加一个域名

    127.0.0.1       zhangbiao.com
    127.0.0.1       admin.zhangbiao.com
    127.0.0.1       buy.zhangbiao.com
    

      

    子域名访问的代码如下  

    from flask import Flask, views, url_for
    
    app = Flask(import_name=__name__)
    app.config['SERVER_NAME'] = 'zhangbiao.com:5000'
    
    
    @app.route("/", subdomain="admin") 返回静态的子域名
    def static_index():
        """Flask supports static subdomains
        This is available at static.your-domain.tld"""
        return "xxxxxx.your-domain.tld"
    
    
    @app.route("/dynamic", subdomain="<username>") # 返回动态的子域名
    def username_index(username):
        """Dynamic subdomains are also supported
        Try going to user1.your-domain.tld/dynamic"""
        print(username)
        return username + ".your-domain.tld"
    
    
    if __name__ == '__main__':
        app.run()

     输入子域名

    http://admin.zhangbiao.com:5000/
    

      

    返回静态子域名如下

      输入子域名

    http://buy.zhangbiao.com:5000/dynamic
    

    返回动态子域名如下  

    自定义正则表达式

     基本的步奏

      1 写一个类 BaseConverter

         2  视情况而定,是否要重构 to_python 和 to_url方法

    to_python 正则匹配成功之后,传入视图函数之前对先匹配的数据,进行二次处理

    to_url 反向生成执行to_url ,在下面实例中在执行url_for的时候执行to_url 

    from flask import Flask, views, url_for
    from werkzeug.routing import BaseConverter
    
    app = Flask(import_name=__name__)
    
    
    # 1. 写RegexConverter类
    class RegexConverter(BaseConverter):
        """
        自定义URL匹配正则表达式
        """
    
        def __init__(self, map, regex):
            super(RegexConverter, self).__init__(map)
            self.regex = regex
    
        def to_python(self, value):
            """
            路由匹配时,匹配成功后传递给视图函数中参数的值
            :param value:
            :return:
            """
            # "123"
            return int(value)
    
        def to_url(self, value):
            """
            使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
            :param value:
            :return:
            """
            val = super(RegexConverter, self).to_url(value)
            return val
    
    
    # 2. 将RegexConverter添加到flask中
    app.url_map.converters['regex'] = RegexConverter
    
    
    @app.route('/index/<regex("d+"):nid>')
    def index(nid):
        print(nid,type(nid))
    
        url_for('index',nid=89)
        return 'Index'
    
    
    if __name__ == '__main__':
        app.run()

     模板

    1 Flask 可以传递函数给模板  2 后端对html进行转义可以使用markup 前端可以用safe

    2 减少前端代码的复用,前端可以定义宏,可以像一个函数一样调用 

    主程序

    from flask import Flask,render_template,Markup,jsonify,make_response
    app = Flask(__name__)
    
    
    def func1(arg):
        return Markup("<input type='text' value='%s' />" %(arg,))
    
    @app.route('/')
    def index():
        # return jsonify({'k1':'v1'})
        return render_template('s10index.html',ff = func1)
    
    if __name__ == '__main__':
        app.run()

    s10index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        {{ff('六五')}}
    
    
        {% macro xx(name, type='text', value='') %}
            <input type="{{ type }}" name="{{ name }}1" value="{{ value }}">
            <input type="{{ type }}" name="{{ name }}2" value="{{ value }}">
            <input type="{{ type }}" name="{{ name }}3" value="{{ value }}">
            <input type="{{ type }}" name="{{ name }}4" value="{{ value }}">
        {% endmacro %}
    
        {{ xx('n') }}
    
    </body>
    </html>

    请求和响应

    请求封装在 request中

    from flask import Flask,request
    

      

    响应

    from flask import Flask,jsonify,make_response
    

      

    from flask import Flask,jsonify,make_response,request
    app = Flask(__name__)
    
    
    @app.route('/')
    def index():
        response =  make_response("asdfasdf")
        response.set_cookie("name", 'zhang')
        return response
    
    
    if __name__ == '__main__':
        app.run()
    

      

    Session

    简单的使用如下

    from flask import Flask,session
    app = Flask(__name__)
    app.secret_key = 'sdfsdf'
    
    @app.route('/')
    def set_session():
        # flask内置的使用 加密cookie(签名cookie)来保存数据。
        session['k1'] = 'v1'
        session['k2'] = 'v2'
        return 'xxx'
    
    @app.route('/get_session')
    def get_session():
        # flask内置的使用 加密cookie(签名cookie)来保存数据。
        k1=session.get('k1','')
        print(k1)
        return 'xxx'
    if __name__ == '__main__':
        app.run()

      

  • 相关阅读:
    Daily Scrum 11.19 部分测试报告
    Daily Scrum 11.16
    Daily Scrum 11.14
    Daily Scrum 11.13
    Daily Scrum 11.12
    Daily Scrum 11.11
    Daily Scrum 11.10
    M1事后分析汇报以及总结
    Alpha阶段个人贡献分及转会人员确定
    项目测试
  • 原文地址:https://www.cnblogs.com/crazymagic/p/9576610.html
Copyright © 2020-2023  润新知