如何正确地将依赖项注入到Flask中?

3

我正在编写我的第一个Flask应用程序。到目前为止,通过以下方式使一切正常(请注意,此代码将分布在多个文件中):

class AppDefinition:

    def __init__(self):
        self.App = Flask(__name__, instance_relative_config = True)
        self.PlacesProvider = GooglePlacesSearchProvider(
            'https://maps.googleapis.com/maps/api/place/findplacefromtext/json',
            'my_api_key')

app = AppDefinition()

@app.App.route('/search/phone/<phone>/<language>')
def search_with_phone_number(phone: str, language: str):
    resp = app.PlacesProvider.get_by_phone_number(phone, language)
    return from_response(resp)

@app.App.route('/search/address/<address>/<language>')
def search_with_address(address: str, language: str):
    resp = app.PlacesProvider.get_by_address(address, language)
    return from_response(resp)

def from_response(resp: Response):
    return json.dumps(resp.json(), ensure_ascii = False)

if __name__ == '__main__':
    HOST = 'localhost'
    PORT = 5000
    app.App.run(HOST, PORT)

然而,我对这段代码并不是特别满意。控制器方法没有封装成合适的类,依赖关系也没有正确注入,似乎没有一种方法可以封装控制器方法。所有这些问题似乎都涉及到核心的依赖注入,所以这可能是真正的问题,我的看法是如此。鉴于这一点,我应该如何在这种情况下进行依赖注入呢?

1个回答

2

使用依赖注入器。以下是您的应用程序的样子。

application.py清单:

import json

from dependency_injector import containers, providers
from dependency_injector.ext import flask
from flask import Flask


# Services

class Response:

    def __init__(self, data):
        self.data = data

    def json(self):
        return self.data


class GooglePlacesSearchProvider:

    def __init__(self, url, api_key):
        ...

    def get_by_phone_number(self, phone, language):
        return Response({'result': 'phone-number-lookup-result'})

    def get_by_address(self, phone, language):
        return Response({'result': 'address-lookup-result'})


# Views

def search_with_phone_number(phone: str, language: str, places_provider: GooglePlacesSearchProvider):
    resp = places_provider.get_by_phone_number(phone, language)
    return from_response(resp)


def search_with_address(address: str, language: str, places_provider: GooglePlacesSearchProvider):
    resp = places_provider.get_by_address(address, language)
    return from_response(resp)


def from_response(resp: Response):
    return json.dumps(resp.json(), ensure_ascii=False)


# Container

class ApplicationContainer(containers.DeclarativeContainer):
    """Application container."""

    app = flask.Application(Flask, __name__, instance_relative_config=True)

    config = providers.Configuration()

    places_provider = providers.Factory(
        GooglePlacesSearchProvider,
        config.services.places.url,
        config.services.places.api_key,
    )

    search_with_phone_number_view = flask.View(
        search_with_phone_number,
        places_provider=places_provider,
    )

    search_with_address_view = flask.View(
        search_with_address,
        places_provider=places_provider,
    )


# Application factory

def create_app():
    container = ApplicationContainer()
    container.config.from_yaml('config.yml')
    container.config.services.places.api_key.from_env('PLACES_API_KEY')

    app = container.app()
    app.container = container

    app.add_url_rule(
        '/search/phone/<phone>/<language>',
        view_func=container.search_with_phone_number_view.as_view(),
    )
    app.add_url_rule(
        '/search/address/<address>/<language>',
        view_func=container.search_with_address_view.as_view(),
    )

    return app


if __name__ == '__main__':
    HOST = 'localhost'
    PORT = 5000
    app = create_app()
    app.run(HOST, PORT)

config.yml清单:

services:
  places:
    url: "https://maps.googleapis.com/maps/api/place/findplacefromtext/json"

当您运行应用程序时,需要将API密钥作为环境变量提供:

PLACES_API_KEY=key python -m application

我建议将其拆分为多个文件。请查看依赖注入器Flask教程


@Yunnosch,感谢您的审阅。已经修改完毕,请问您觉得怎么样? - Roman Mogylatov
:-) 看起来现在是一个解释完整的答案了。请理解我缺乏实际的技术理解,无法判断它是否是一个值得点赞的有帮助和正确的答案。但它绝对是一个答案。 - Yunnosch
明白了,谢谢,没问题。顺便说一下,我完全同意并理解你所担心的问题。我匆忙回答,初始答案并不太有用。我很高兴像你这样的人关注社区。我会继续跟进和传播这种文化。 - Roman Mogylatov
哇,太完美了。比我所期望的更多。 - Yunnosch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接