Alex Poca
Alex Poca

Reputation: 2566

Using routes in classes

I am trying to rewrite some working code as a class.

A minimal working code:

from flask import Flask

app = Flask(__name__)

@app.route("/1")
def func_1():
    return "view 1"

@app.route("/2")
def func_2():
    return "view 2"

app.run()

How to write it as a class with the route defined during the object instantiation?

I only want it clean: after instantiating an object I want the respective route already working with no extra lines of code.

This is the closest I get to:

from flask import Flask

class NewView:

    def __init__(self, url, string):
        self.string = string
        self.server = Flask(__name__)
        self.server.add_url_rule(url, 'index', self.index)

    def index(self):
        return self.string

v1 = NewView("/1", "view 1")
v2 = NewView("/2", "view 2")

v1.server.run()

This, of course, recognizes /1 as route for v1.index(), but /2 doesn't work.

The ideal would be something like the following but I cannot make it work:

from flask import Flask

app = Flask(__name__)

class NewView:

    def __init__(self, url, string):
        ....
        app.add_url_rule(url, ...?..., self.index)

    def index(self):
        return self.string

v1 = NewView("/1", "view 1")
v2 = NewView("/2", "view 2")

app.run()

Upvotes: 0

Views: 440

Answers (2)

Ken Kinder
Ken Kinder

Reputation: 13140

First, your mistake:

def __init__(self, url, string):
    self.string = string
    self.server = Flask(__name__)
    self.server.add_url_rule(url, 'index', self.index)

Because you have two instances of this class, there are two Flask objects. You only run the second one.

What you're immediately trying to do can be done like this:

import flask

# There can be only one!
app = flask.Flask(__name__)


class MyView:
    def __init__(self, url, name, string):
        self.url = url
        self.string = string
        app.add_url_rule(url, name, self.serve)

    def serve(self):
        return self.string


view1 = MyView('/1', name='view1', string='This is View 1.')
view2 = MyView('/2', name='view2', string='This is View 2, not view 1.')

app.run()

The above code will work and do what you expect. Something to note is that, since Flask likes names for unique routes, I have you passing in a name for each route. That way, url_for('view1') and url_for('view2') work.

Having said all that, the community has largely already accomplished much of this Pluggable Views. Check it out.

Upvotes: 1

gonczor
gonczor

Reputation: 4136

I think that if your goal is to keep code clean, you should avoid creating objects that are never used. The class based views in flask. The as_view() method that is being passes is class method, so also here there is no need to create a never used object. The process of registring urls belongs to creation of an app, not separate objects (that's how it works in Django for instance). If I were you I would go with something similar to this:

from flask import Flask
from flask.views import View

def init_app():
    app = Flask(__name__)
    app.add_url_rule('/', view_func=NewView.as_view('index'))
    return app


class NewView(View):

    def dispatch_request(self):
        return 'Test'

app = init_app()
app.run()

Upvotes: 0

Related Questions