Объектно-ориентированный Python с Flask Server?

Я использую Flask, чтобы выставить некоторый хрустящий код в качестве веб-сервиса. Я хотел бы иметь некоторые переменные класса, к которым могут обращаться мои функции Flask.

Позвольте мне провести вас туда, где я застрял:

from flask import Flask
app = Flask(__name__)

class MyServer:
  def __init__(self):
    globalData = json.load(filename)

  @app.route('/getSomeData')
  def getSomeData():
    return random.choice(globalData) #select some random data to return

if __name__ == "__main__":
  app.run(host='0.0.0.0')

Когда я запускаю getSomeData() вне Flask, он работает нормально. Но, когда я запускаю это с помощью Flask, я получаю 500 internal server error. Здесь нет волшебства, и Флакс не знает, что он должен инициализировать объект MyServer. Как я могу передать экземпляр MyServer команде app.run()?

Я мог бы признать поражение и поместить globalData в базу данных. Но есть ли другой путь?

Ответ 1

Вы можете создать экземпляр MyServer только за пределами ваших конечных точек и получить доступ к его атрибутам. Это сработало для меня:

class MyServer:
    def __init__(self):
        self.globalData = "hello"

from flask import Flask
app = Flask(__name__)

my_server = MyServer()

@app.route("/getSomeData")
def getSomeData():
    return my_server.globalData

if __name__ == "__main__":
    app.run(host="0.0.0.0")

Ответ 2

Наименее связанное решение заключается в применении маршрутов во время выполнения (а не во время загрузки):

def init_app(flask_app, database_interface, filesystem_interface):
    server = MyServer(database_interface, filesystem_interface)
    flask_app.route('get_data', methods=['GET'])(server.get_data)

Это очень легко проверить - просто вызовите init_app() в тестовом коде с помощью фальшивых/поддельных зависимостей (database_interface и filesystem_interface) и флеш-приложение, настроенное для тестирования (app.config["TESTING"]=True или что-то вроде это), и вы все готовы писать тесты, которые охватывают все ваше приложение (включая маршрутизацию фляжек).

Единственный недостаток - это не очень "Flasky" (или так мне сказали); идиома Flask должна использовать @app.route(), которая применяется во время загрузки и обязательно жестко связана, потому что зависимости жестко закодированы в реализации вместо того, чтобы впрыскиваться в какой-либо конструктор или метод factory (и, следовательно, сложно тестировать).

Ответ 3

немного поздно, но это быстрый вариант, который я использую для регистрации маршрутов во время init

from flask import Flask,request,render_template
from functools import partial


registered_routes = {}
def register_route(route=None):
    #simple decorator for class based views
    def inner(fn):
        registered_routes[route] = fn
        return fn
    return inner

class MyServer(Flask):
    def __init__(self,*args,**kwargs):
        if not args:
            kwargs.setdefault('import_name',__name__)
        Flask.__init__(self,*args ,**kwargs)
        # register the routes from the decorator
        for route,fn in registered_routes.items():
            partial_fn = partial(fn,self)
            partial_fn.__name__ = fn.__name__
            self.route(route)(partial_fn)


    @register_route("/")
    def index(self):
        return render_template("my_template.html")

if __name__ == "__main__":
    MyServer(template_folder=os.path.dirname(__file__)).run(debug=True)

Ответ 4

если вы хотите подойти к классу MyServer как ресурс
Я считаю, что flask_restful может вам помочь:

from flask import Flask
from flask_restful import Resource, Api
import json
import numpy as np

app = Flask(__name__)
api = Api(app)

class MyServer(Resource):
    def __init__(self):
        self.globalData = json.load(filename)

    def get(self):
        return np.random.choice(self.globalData)

api.add_resource(MyServer, '/')

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

Ответ 5

Вы можете наследовать свой класс из Flask, чтобы вы могли добавить к нему функциональные возможности:

class MyServer(Flask):
    def __init__(self, name):
        self.globalData = "hello"
        Flask.__init__(self, name)

    def getSomeData(self):
        return self.globalData

my_server = MyServer(__name__)


@my_server.route("/getSomeData") 
def getSomeData():
    return my_server.getSomeData()

my_server.run(host="0.0.0.0")

Теперь я пытаюсь использовать декоратор маршрута для метода моего класса MyServer, но пока не могу понять.

Ответ 6

Попробуй флягу

Я только начал с этого, и это именно то, что я искал.

http://flask-classful.teracy.org/#

Ответ 7

Я знаю, что это поздний ответ, но я столкнулся с этим вопросом, когда столкнулся с аналогичной проблемой. Я нашел классную колбу действительно хорошей. Вы наследуете свой класс от FlaskView и регистрируете приложение Flask в своем классе MyServer.

http://flask-classful.teracy.org/#

В этом случае с классом flask ваш код будет выглядеть так:

from flask import Flask
from flask-classful import FlaskView, route

app = Flask(__name__)

class MyServer(FlaskView):
  def __init__(self):
    globalData = json.load(filename)

  @route('/getSomeData')
  def getSomeData():
    return random.choice(globalData) #select some random data to return


MyServer.register(app, base_route="/")


if __name__ == "__main__":
  app.run(host='0.0.0.0')