3

在 Flask 中,您可以将类和装饰器用于路由。每个用例的优势是什么?

我正在考虑静态页面的装饰器和更多动态页面的类。如果我要将龙卷风/独角兽与烧瓶结合起来,这是更好的方法。

我打算使用异步方法,以此为例作为起点: 同时使用 Flask 和 Tornado?

这篇文章指出它可能依赖于框架,但在烧瓶中我们可以同时使用两者。
python web开发中的装饰器与类

4

2 回答 2

2

这些是我个人的经验法则。

  1. 如果我必须从现有应用程序移植,我使用源应用程序中使用的约定。拥有两种可能的路由样式是一大优势。
  2. 如果应用程序对相同的代码使用不同的 URL,我会在 URL 和处理程序类之间创建一个显式映射。
  3. 如果应用程序中使用的 URL 和类的数量很少,我将使用装饰器。
  4. 如果应用程序很复杂,具有复杂的 URL,我会在 URL 和处理程序类之间创建一个映射。
于 2012-09-11T16:18:40.840 回答
1

从下面的 MVP 代码中可以看出,当我将实现许​​多 REST API 动词时,我通常发现我喜欢基于类的路由,很可能围绕数据库表等资源。这在使用其他装饰器时也有利于清晰,并且您还可以选择哪个动词可能具有某个装饰器。

或者,我将使用装饰方法来实现为静态页面返回 html 的路由,我只需要 GET 动词。

from flask import Flask
from flask_restful import Api, Resource, reqparse, abort, fields, marshal_with
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
api = Api(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
db = SQLAlchemy(app)

class VideoModel(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    views = db.Column(db.Integer, nullable=False)
    likes = db.Column(db.Integer, nullable=False)

    def __repr__(self):
        return f"Video(name = {name}, views = {views}, likes = {likes})"

video_put_args = reqparse.RequestParser()
video_put_args.add_argument("name", type=str, help="Name of the video is required", required=True)
video_put_args.add_argument("views", type=int, help="Views of the video", required=True)
video_put_args.add_argument("likes", type=int, help="Likes on the video", required=True)

video_update_args = reqparse.RequestParser()
video_update_args.add_argument("name", type=str, help="Name of the video is required")
video_update_args.add_argument("views", type=int, help="Views of the video")
video_update_args.add_argument("likes", type=int, help="Likes on the video")

resource_fields = {
    'id': fields.Integer,
    'name': fields.String,
    'views': fields.Integer,
    'likes': fields.Integer
}

class Video(Resource):
    @marshal_with(resource_fields)
    def get(self, video_id):
        result = VideoModel.query.filter_by(id=video_id).first()
        if not result:
            abort(404, message="Could not find video with that id")
        return result

    @marshal_with(resource_fields)
    def put(self, video_id):
        args = video_put_args.parse_args()
        result = VideoModel.query.filter_by(id=video_id).first()
        if result:
            abort(409, message="Video id taken...")

        video = VideoModel(id=video_id, name=args['name'], views=args['views'], likes=args['likes'])
        db.session.add(video)
        db.session.commit()
        return video, 201

    @marshal_with(resource_fields)
    def patch(self, video_id):
        args = video_update_args.parse_args()
        result = VideoModel.query.filter_by(id=video_id).first()
        if not result:
            abort(404, message="Video doesn't exist, cannot update")

        if args['name']:
            result.name = args['name']
        if args['views']:
            result.views = args['views']
        if args['likes']:
            result.likes = args['likes']

        db.session.commit()

        return result


    def delete(self, video_id):
        abort_if_video_id_doesnt_exist(video_id)
        del videos[video_id]
        return '', 204


api.add_resource(Video, "/video/<int:video_id>")

if __name__ == "__main__":
    app.run(debug=True)
于 2020-09-23T03:57:27.800 回答