Victor Sigler
Victor Sigler

Reputation: 23459

Define manually routes using Flask

I want to define routes manually to some method of classes, something like this :

class X:

    def route1():
       #do stuff here

    def route2():
       #do stuff here

and then make something like this :

app.add_url_rule('/x/', view_func=X.route1())
app.add_url_rule('/y/', view_func=X.route2())

It's possible?? What's the correct way to acomplish this?

Upvotes: 11

Views: 9470

Answers (3)

seaders
seaders

Reputation: 4106

If you're talking about flask's helper decorator, app.route(...), don't forget, it's just a decorator, and you can always just call the returned wrapper of a decorator.

With a nonsense, do-nothing wrapper like,

def some_wrapper():
    def wrapper(fn):
        return fn()
    return wrapper

When you wrap a func like,

@some_wrapper
def some_func():
    print('Hello World')

For all intents and purposes, what might as well be happening is,

def some_func():
    print('Hello World')

some_func = some_wrapper()(some_func)

So, because of that, you can call app.route just like you can any decorator,

app.route('/x/')(X.route1)

This ends up doing exactly the same as @sean-vieira's bit of his answer - app.add_url_rule('/x/', view_func=INSTANCE_X.route1).

But one reason you might prefer it is because it follows the "regular" path of flask, and flask docs.

For my use, the reason I use it is to chain some routes which I add programatically,

suffix = 'ducky'

app.route(f'secure_initial_route_for_{suffix}', endpoint=f'secure_{suffix}')(
    roles_required('admin')(secured_fn))
app.route(f'secure_sub_route_for_{suffix}', endpoint=f'secure_sub_{suffix}')(
    roles_required('admin')(secured_sub_fn))

That is how I some of my use cases.

Upvotes: 0

lealhugui
lealhugui

Reputation: 177

Like I said in the comments, do you know flask-classy?

From their exemple:

from flask import Flask
from flask.ext.classy import FlaskView

# we'll make a list to hold some quotes for our app
quotes = [
    "A noble spirit embiggens the smallest man! ~ Jebediah Springfield",
    "If there is a way to do it better... find it. ~ Thomas Edison",
    "No one knows what he can do till he tries. ~ Publilius Syrus"
]

app = Flask(__name__)

class QuotesView(FlaskView):

    def index(self):
        return "<br>".join(quotes)

    def get(self, id):
        id = int(id)
        if id < len(quotes) - 1:
            return quotes[id]
        else:
            return "Not Found", 404     

QuotesView.register(app)

if __name__ == '__main__':
    app.run()

Would generate automatically routes for http://foobar.foo/quotes and http://foobar.foo/quotes/<id>

Upvotes: 5

Sean Vieira
Sean Vieira

Reputation: 160073

There are several ways to do this:

  1. Create a global instance of your class and route your rules to it:

    class X(object):
        # Your code here
    
    INSTANCE_X = X()
    
    # Note that we are not *calling* the methods
    app.add_url_rule('/x/', view_func=INSTANCE_X.route1)
    app.add_url_rule('/y/', view_func=INSTANCE_X.route2)
    
  2. Create an instance in the view function and delegate to it:

    # Using both methods of registering URLs here
    # just to show that both work
    
    @app.route('/x/')
    def handle_route1():
        return X().route1()
    
    def handle_route2():
        return X().route2()
    
    app.add_url_rule('/y/', view_func=handle_route2)
    
  3. Inherit from Flask's View or MethodView Pluggable View classes and use the as_view classmethod to handle this for you:

    class X(View):
        methods = ['GET']
    
        def dispatch_request(self):
            if request.path == '/x/':
                return route1()
            elsif request.path == '/y/':
                return route2()
            else:
                abort(404)
    
    app.add_url_rule('/x/', view_func=X.as_view('X.route1'))
    app.add_url_rule('/y/', view_func=X.as_view('X.route2'))
    

Upvotes: 14

Related Questions