zoukankan      html  css  js  c++  java
  • 3. 视图的简单玩法

    preface

    我这里主要说说视图的玩法

    1. 响应
    2. 静态文件管理
    3. 即插视图
      3.1. 标准视图
      3.2. 基于调度方法的视图
    4. 蓝图
    5. 子域名

    响应

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

    • 如果返回yied合法的响应对象,它会从视图直接返回。
    • 如果返回一个字符串,会用字符串数据和默认的参数创建以字符串为主体,状态为200,MIME类型是text/html的werkzeug.wrapper.Response 响应对象。
    • 如果返回的一个元组,,且元组中的元素可以提供额外的信息。这样的元组必须是(response,status,headers) 的形式,但是需要至少一个包含一个元素。status的值会覆盖状态代码,header可以是一个列表或者字典,作为额外的消息头。
    • 如果上诉条件均不满足,Flask会假设返回值是一个合法的WSGI的应用程序,并通Response.force_type(rv,request.environ)转换为一个请求对象。

    请看代码

    @app.error_handler(404)
    def not_found(error):
        return render_template('templates/error.html'),404
    

    上面的代码满足第3条,返回的元组必须是(response,status,headers) 的形式。
    我们可以改为如下显式的调用make_response形式。

    @app.error_handlers(404)
    def not_found(error):
        resp = make_response(render_template('error.html'),404)
        return resp
    

    第二种方法很灵活,可是添加一些额外的工作,比如设置cookie,头信息等。
    API 都是返回JSON格式的响应,需要包装jsonify。可以抽象下,让Flask自动帮我们完成这些工作。

    
    from flask import Flask,jsonify
    from werkzeug.wrappers import Response
    
    app = Flask(__name__)
    
    class JSONResponse(Response):
        @classmethod
        def force_type(cls, rv, environ=None):
            if isinstance(rv,dict):
                rv = jsonify(rv)
            return super(JSONResponse,cls).force_type(rv,environ)
    
    
    app.response_class = JSONResponse
    
    @app.route('/')
    def hello_wolrd():
        return {'msg':'hello world'}
    
    
    @app.route('/custome_headers')
    def headers():
        return {'headers':[1,2,3]},201,[('X-Request-Id','100')]
    
    if __name__ == '__main__':
        app.run(port=80)
    

    httpie是一个使用python编写的,提供了语法高亮,JSON支持,可以替代curl的工具,它也可以方便的集成到Python项目中。

    pip install httpie  # 安装
    

    我们使用http查看下:

    [root@localhost ~]# http http://0.0.0.0/custome_headers
    HTTP/1.0 201 CREATED
    Content-Length: 45
    Content-Type: application/json
    Date: Tue, 04 Apr 2017 04:01:55 GMT
    Server: Werkzeug/0.12.1 Python/2.7.5
    X-Request-Id: 100
    
    {
        "headers": [
            1,
            2,
            3
        ]
    }
    

    静态文件管理

    web应用大多数会提供静态文件服务一边给用户更好的访问体验。静态文件主要包含CSS样式文件、javascript脚本文件、图片文件和字体文件等静态资源。Flask也支持静态文件访问,默认只需要在项目根目录下创建名字为static的目录,在应用中使用“/static” 开头的路径就可以访问。但是为了获得更好的处理能力,推荐使用Nginx或者其他的web服务器管理静态文件。
    不要直接在模版中写静态文件路径,应该使用url_for生成路径。举个列子:

    url_for('static',filename='style.css')
    

    生成的路径就是'/static/style.css'。当然,我们也可以定制静态文件的真实目录:

    app = Flask(__name__,static_folder='/tmp')
    

    那么访问“http://127.0.0.1/static/style.css”就是访问的是/tmp/style.css这个文件。

    即插视图

    即插视图灵感来自于django的基于类而不是函数的通用视图方式,这样的视图就可以支持继承了。视图类型有2种类型:
    1.标准视图
    标准视图需要继承flask.views.View,必须实现dispatch_request。
    看一个例子:

    # coding=utf-8
    from flask import Flask, request, render_template
    from flask.views import View
    
    app = Flask(__name__, template_folder='templates/')  # 指定模版文件
    
    
    class BaseView(View):
        def get_template_name(self):
            raise NotImplementedError()
    
        def dispatch_request(self):
            if request.method != 'GET':
                return 'UNSUPPORTED!'
            context = {'users': self.get_users()}
            print('context',context)
            return render_template(self.get_template_name(),**context)   # 必须是**content,render_template源码写的就是这样。
    
    
    class UserView(BaseView):
    
        def get_template_name(self):
            return 'chapter3/section1/users.html'  # html文件名字
    
        def get_users(self):
            return [{
                'username': 'fake',    
                'avatar': 'http://lorempixel.com/100/100/nature/'  # 用户头像
            }]
    
    
    app.add_url_rule('/users', view_func=UserView.as_view('userview'))  # 添加一条URL规则,且该URL对应的视图方法
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=80, debug=True)
    

    2.基于调度方法的视图

    flask.views.MethodView 对每个HTTP方法执行不同的函数(映射到对应方法的小写的同名方法上),这对RESTful API尤其有用。看一个例子。

    # coding=utf-8
    from flask import Flask, jsonify
    from flask.views import MethodView
    
    app = Flask(__name__)
    
    
    class UserAPI(MethodView):
    
        def get(self):
            return jsonify({
                'username': 'fake',
                'avatar': 'http://lorempixel.com/100/100/nature/'
            })
    
        def post(self):
            return 'UNSUPPORTED!'
    
    
    app.add_url_rule('/user', view_func=UserAPI.as_view('userview'))
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=80)
    

    解释下as_view的功能: 上面的例子是将类UserAPI使用as_view 作为视图函数 然后设置一个name 之后与/user 的 url规则绑定在一起。

    即插视图继承view 实现一个自己的dispatch_request的方法。 在执行这个视图的时候会执行dispath_request这个函数里的内容,这样就可以灵活运用这个特性。
    通过as_view的返回值来实现对于视图的装饰功能,常用于权限的检查,登陆验证等。

    def user_required(f):
        def decorator(*args,**kwargs):
            if not g.user:
                abort(401)
            return f(*args,**kwargs)
        return decorator
    
    view = user_requird(UserAPI.as_view('users'))
    app.ad_url_rule('/users/',view_func=view)
    

    从Flask 0.8开始,还可以通过在继承MethodView类中添加 decorators 属性来实现对视图的装饰:

    class UserAPI(methodView)
        decorators = [user_required]
    

    这样的话,用户在访问的时候,我们可以对用户进行验证与权限检测了。

    蓝图

    蓝图(blueprint)实现了应用的模块化,使用蓝图让应用层次清晰,开发者可以更容易的开发和维护项目。蓝图通常作用于相同的URL前缀,比如/user/:id、/user/profile 这样的地址,都是以/user开头的,那么他们就可以放在一个模块中。看一个最简单的例子, 我感觉这个蓝图功能就等于django的url里面的include功能一样,匹配到第一个url路径后往对应app里面走。
    某个app的下面的simple.py

    from flask import Blueprint
    bp = Blueprint('user',__name__,url_prefix='/user')
    
    @bp.route('/')
    def index():
        return "User's Index Page"
    

    然后我们看主程序(注册到里面即可)

    import blueprint
    app.register_blueprint(blueprint.bp)   # 注册到里面即可
    

    子域名

    现在很多SaaS应用为用户提供一个子域名来访问,可以借助subdomain来实现同样的功能。
    请看例子:

    # coding=utf-8
    from flask import Flask, g
    
    app = Flask(__name__)
    app.config['SERVER_NAME'] = 'example.com'
    
    
    @app.url_value_preprocessor
    def get_site(endpoint, values):
        g.site = values.pop('subdomain')
    
    
    @app.route('/', subdomain='<subdomain>')
    def index():
        return g.site
    
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=80)
    
    

    然后我们访问的效果如下:

    [root@localhost ~]# http http://a.example.com/ --print b
    a
    
    [root@localhost ~]# http http://b.example.com:80/ --print b
    b
    
  • 相关阅读:
    谈谈关于个人提升的一些思考
    asp.net 委托用法
    DNN 配置 数据库篇
    一个技术为主的博客沦落为娱乐休息的场所
    NDO 组件和例子下载,内置了一个基于Velocity模版引擎的代码生成器
    DNN 研究路线图
    学习DNN开发模块插件的几条主线
    NDO 快速入门
    NDO 简介
    也谈代码生成器
  • 原文地址:https://www.cnblogs.com/liaojiafa/p/6664778.html
Copyright © 2011-2022 走看看