Atterratio
Atterratio

Reputation: 466

How use flask route with class based view?

Django style Class Based Views cool and powerful feature. But Flask style routers more suitable to the free style of app structure. How can I do something like this:

@app.route("/")
class MyView(MethodView):
    def get(self):
        return "Hello word"

Upvotes: 3

Views: 14556

Answers (3)

makeroo
makeroo

Reputation: 527

I fancy D.I. and prefer the approach described below:

class MyBlueprint:
    def __init__(self, ...some resources...):
        self.resources = ...
        self.blueprint = Blueprint('youdomus_blueprint', __name__)

        self.blueprint.add_url_rule('/my-route', view_func=self.my_method)

    def my_method(self):
        ...

app = Flask(__name__)
app.register_blueprint(MyBlueprint(...).blueprint)

Below a running example. A sample module bp_example.py contains some application logic class:

from flask import Blueprint, jsonify, request

class Greeter:
    def __init__(self, greetings: str, default_name: str):
        self.blueprint = Blueprint('flask_example', __name__)
        self.blueprint.add_url_rule('/a-method', view_func=self.a_method)
        self.greetings = greetings
        self.default_name = default_name

    def a_method(self):
        return jsonify(f'{self.greetings}, {request.args.get("name") or self.default_name}')

The main module use it like this:

def main():
    import sys
    from bp_example import Greeter

    greeter = Greeter(
        greetings=sys.argv[1] if len(sys.argv) > 1 else 'Hello',
        default_name=sys.argv[2] if len(sys.argv) > 2 else 'World',
    )

    from flask import Flask

    app = Flask(__name__)
    app.register_blueprint(greeter.blueprint)

    app.run(port=5000)

if __name__ == '__main__':
    main()

What's important here is that Blueprint routes definitions need an instance, not a class, otherwise you end with some globals around and unit testing becomes a mess.

Upvotes: -1

apet
apet

Reputation: 1098

from flask documentation(https://flask.palletsprojects.com/en/1.1.x/views/):

from flask.views import View

class ShowUsers(View):
    def dispatch_request(self):
        users = User.query.all()
        return render_template('users.html', objects=users)

app.add_url_rule('/users/', view_func=ShowUsers.as_view('show_users'))

the last string converts to the function and does registration(@app.route(...)) to the app

Upvotes: 9

Atterratio
Atterratio

Reputation: 466

I could not find such feature in the official flask documentation. And also I did not find any solution on the internet or a similar question at Stack Overflow, so I prepared a snippet for this case.

import types

from flask import Blueprint
from flask.views import MethodView


# decorator code
def class_route(self, rule, endpoint, **options):
    """
    This decorator allow add routed to class view.
    :param self: any flask object that have `add_url_rule` method.
    :param rule: flask url rule.
    :param endpoint: endpoint name
    """

    def decorator(cls):
        self.add_url_rule(rule, view_func=cls.as_view(endpoint), **options)
        return cls

    return decorator

    # Usage
    # I use `Blueprint` and `MethodView`, but it should work correct with `App` and `View` to.


bp = Blueprint("bp", __name__, template_folder="templates")


@class_route(bp, "/", "my_view")
class MyView(MethodView):
    def get(self):
        return "Hello world"


# Advanced usage
# Add decorator as class method
bp.class_route = types.MethodType(class_route, bp)


# And use is as bultin decorator
@bp.class_route("/advanced", "advanced_my_view")
class AdvancedMyView(MethodView):
    def get(self):
        return "Hello world!"

Upvotes: 3

Related Questions