zoukankan      html  css  js  c++  java
  • Flask入门

    Web框架的本质是什么?

    对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。

    参考:http://www.cnblogs.com/wupeiqi/articles/5237672.html

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

      

    wsgi是什么?

    Web Server Gateway Interface/web服务网关接口,是一套协议规范。

    python标准库提供的独立WSGI服务器称为wsgiref(Django没有自己实现socket,而是采用的wsgiref模块)。

    wsgiref 、werkzeug以及uwsgi都是实现了 wsgi协议(规范)的模块。

    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__':
        httpd = make_server('', 8080, RunServer)
        print("Serving HTTP on port 8080...")
        httpd.serve_forever()

    Flask简介

    参考:http://www.cnblogs.com/wupeiqi/articles/7552008.html

    Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架。

    Flask示例

    Flask demo01  (有参装饰器方式,参考:http://www.cnblogs.com/standby/p/8271157.html

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/index')
    def index():
        return "Index"
    
    if __name__ == '__main__':
        app.run()
    

    Flask demo02  (类似Django的方式)

    from flask import Flask
    
    app = Flask(__name__)
    
    def index():
        return "Index"
    
    app.add_url_rule('/index','reverse_url_name',index)
    
    if __name__ == '__main__':
        app.run()

    Flask依赖实现了wsgi协议的模块:werkzeug

    werkzeug不依赖Flask,自己单独可以运行。

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

      

    werkzeug.serving.run_simple 这个方法前两个参数是ip和port,第三个参数是函数,那么当然也可以是对象喽。 
    再结合上面的Flask Demo程序,
    
    app.run()
    run_simple(host, port, self, **options)
    那么这个self就是 app 这个object,所以 app() 这样就调用了 app.__call__方法
    
    def __call__(self, environ, start_response):
        """Shortcut for :attr:`wsgi_app`."""
        return self.wsgi_app(environ, start_response)
    
    故:Flask应用的入口就是 wsgi_app(...) 这里。
    
    __call__方法干了什么?
    	- 一旦请求到达,执行app.__call__方法
    	- __call__方法封装用户请求(封装成一个request对象)
    	- 进行路由匹配
    

      

    @app.route('/index')
    def index():
        return "Index"

    本质是什么?

    是用一个带参数的装饰器装饰了 index函数

    详见:

    def route(self, rule, **options):
        """A decorator that is used to register a view function for a
        given URL rule.  This does the same thing as :meth:`add_url_rule`
        but is intended for decorator usage::
    
            @app.route('/')
            def index():
                return 'Hello World'
    
        For more information refer to :ref:`url-route-registrations`.
    
        :param rule: the URL rule as string
        :param endpoint: the endpoint for the registered URL rule.  Flask
                         itself assumes the name of the view function as
                         endpoint
        :param options: the options to be forwarded to the underlying
                        :class:`~werkzeug.routing.Rule` object.  A change
                        to Werkzeug is handling of method options.  methods
                        is a list of methods this rule should be limited
                        to (``GET``, ``POST`` etc.).  By default a rule
                        just listens for ``GET`` (and implicitly ``HEAD``).
                        Starting with Flask 0.6, ``OPTIONS`` is implicitly
                        added and handled by the standard request handling.
        """
        def decorator(f):
            endpoint = options.pop('endpoint', None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator
    
    所以 @app.route('/index') 即 @decorator
    
    @decorator
    def index():
        return "Index"
    
    
    def decorator(index):
    	endpoint = options.pop('endpoint', None)
        self.add_url_rule(rule, endpoint, index, **options)
        return index
    
    最后:
    
    self.add_url_rule 里进一步调用:
        # 首先把路由关系封装到一个Rule对象里,类似于{'url':'/index', 'method':index}
        rule = self.url_rule_class(rule, methods=methods, **options)
        rule.provide_automatic_options = provide_automatic_options
        # 其次将路由关系添加到一个 Map对象里,类似于一个保存路由关系的列表。
        self.url_map.add(rule)
    

    所以,最后所有的路由关系就保存在了app.url_map字段里了。

    Django和Flask比较

    Django
    	- 无socket,用的第三方wsgi模块
    	- 中间件
    	- 路由系统
    	- 视图(CBV 和 FBV)
    	- 模板
    	- ORM
    	- cookie 
    	- session
    	- Admin
    	- Form
    	- 缓存
    	- 信号
    	- 序列化
    	- ...
    
    Flask  轻量级框架
    	- 无socket,用的第三方wsgi模块
    	- 中间件(功能比较弱,需要加上扩展)
    	- 路由系统
    	- 视图(CBV 和 FBV)
    	- 无模板,用第三方Jinja2模板
    	- 无ORM
    	- cookie    
    	- session(比较弱)
    

    Flask简单登录示例

    from flask import Flask
    from flask import render_template
    from flask import make_response
    from flask import redirect
    from flask import request
    from flask import session
    
    
    app = Flask(__name__)
    app.secret_key = 'ahlaskdfhzxadqax'  # "加盐":用这个key把用户信息加密返回给客户端,当做cookie存储在客户端浏览器中,减少服务端压力。
    # app = Flask(__name__,template_folder='my_templates',root_path='xxx',static_url_path='/static_file_prefix')
    # print(app.root_path)
    # @app.route('/login')  默认的method只有 GET
    # @app.route('/login',endpoint='alias_name')  endpoint参数用于指定别名,从而可以反向生成url,使用url_for(alias_name)则可以拿到对应url
    
    @app.route('/login',methods=['GET','POST'])
    def login():
        if 'GET' == request.method:
            # print(request.query_string)
            return render_template('login.html')
        elif 'POST' == request.method:
            '''
            print(request)  # <Request 'http://127.0.0.1:5000/login?v=123' [POST]>
            print(request.values)  # CombinedMultiDict([ImmutableMultiDict([('v', '123')]), ImmutableMultiDict([('user', 'alex'), ('pwd', 'xxxooo')])])
            print(request.form)  # ImmutableMultiDict([('user', 'alex'), ('pwd', 'xxxooo')])
            print(request.data)  # b''
            print(request.query_string)  # b'v=123'
            '''
            name = request.form.get('name')
            pwd = request.form.get('pwd')
            if 'alex' == name and '123' == pwd:
                session['user_info'] = name
                return redirect('/index')
            else:
                # return render_template('login.html',msg='用户名或密码错误')
                return render_template('login.html',**{'msg':'用户名或密码错误'})
    
    @app.route('/index',methods=['GET'])
    def index():
        if not session.get('user_info'):
            return redirect('/login')
        response = make_response("这是首页")
        return response
    
    if __name__ == '__main__':
        app.run()
    

      

    Flask 装饰器登录session验证demo

    import functools 
    
    def auth(func):
    	@functools.wraps(func)
    	def inner(*args,**kwargs):
    		user_info = session.get('user_info')
    	    if not user_info:
    	        return redirect('/login')
    		return func(*args,**kwargs)
    	return inner
    
    # @app.route('/index',methods=['GET'],endpoint='n1')
    @app.route('/index',methods=['GET'])
    @auth
    def index():
        return render_template('index.html')
    

      

      

    参考:http://www.cnblogs.com/wupeiqi/articles/7552008.html

    Flask官网:http://flask.pocoo.org/docs/0.10/

    Flask中文版指南:http://docs.jinkan.org/docs/flask/

    作者:Standby一生热爱名山大川、草原沙漠,还有妹子
    出处:http://www.cnblogs.com/standby/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    js-禁止微信H5页面点击右上角菜单时出现“复制链接”,且分享仅支持微信分享
    js-获取用户移动端网络类型:wifi、4g、3g、2g...
    小程序-云开发部署流程(步骤二)
    小程序-(报错)请使用 2.2.3 或以上的基础库以使用云能力(步骤一)
    解决iOS10的Safari下Meta设置user-scalable=no无效的方法
    领域驱动, 事件驱动,测试驱动
    spring web项目中整合netty, akka
    why rpc
    nginx配置https证书
    org.apache.http.NoHttpResponseException
  • 原文地址:https://www.cnblogs.com/standby/p/8476779.html
Copyright © 2011-2022 走看看