Как поделиться экземпляром flask-pymongo в обработчике маршрутов API

Я пытаюсь разработать простой API, используя flask, flask-restplus и flask-pymongo, но я столкнулся с одной структурной конструкцией, основанной на импорте и совместном использовании переменных, я никак не могу получить доступ к БД.

Вот мой код в моем основном файле движка:

app = Flask(__name__)
db = PyMongo(app)

api = Api(app)

from auth import namespace as ns1
api.add_namespace(registerNamespace.api)


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

Но в то же время я хотел бы получить доступ к экземпляру db в реальной реализации API:

from engine import engine

api = Namespace('register', description="Registration")

db = engine.db

@api.route('/whatever')
Class Whatever():
 def get(self):
    db.doSomething();
    return "Simple getter"

Я получаю следующую ошибку.

ImportError: cannot import name engine

Я пытался исправить это в течение довольно долгого времени, потому что я не думаю, что это настолько глупое структурное решение, но я, вероятно, ошибаюсь. Какие способы, будь то структурные или импортные, могут помочь исправить это?

Заранее спасибо!


person Mumrau    schedule 18.01.2018    source источник
comment
Похоже, я нашел способ заставить его работать, а именно поместить импорт внутри функции get(self): , но, честно говоря, это выглядит просто ужасно...   -  person Mumrau    schedule 18.01.2018


Ответы (1)


Существует множество подходов к архитектуре вашего фляжного приложения для простого совместного использования ресурсов. Однако я предпочитаю связывать ресурсы с общим пакетом, обычно с пакетом приложения, чтобы другие модули могли импортировать ресурсы из этого пакета.

Скажем, у нас есть вымышленный проект demo со следующей структурой:

.
├── api
│   ├── __init__.py
│   └── namespace1.py
└── demo
    ├── __init__.py
    ├── main.py
    └── setup.py

Обратите внимание, у нас есть отдельный API в виде отдельного пакета.

Вот краткое описание содержимого отдельных модулей.

демонстрация/__init__.py

db = None # initials package level name to None. 

демонстрация/setup.py

from flask import Flask
from flask_pymongo import PyMongo

import demo

app = Flask('demo')
demo.db = PyMongo(app)  # Here is where we bind the shared resource to the package level name.

демонстрация/main.py

from demo.setup import app
from api import register_api

register_api(app)

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

Наш API может легко импортировать из demo:

api/namespace1.py

from flask_restplus import Namespace, Resource, fields

from demo import db  # Look ma!, it's easy to share resources.
...

@ns.route('/')
class CatList(Resource):
    @ns.doc('list_cats')
    @ns.marshal_list_with(cat)
    def get(self):
        '''List all cats'''
        print(db)
        return CATS

Вы можете просмотреть полный образец здесь.

person Oluwafemi Sule    schedule 20.01.2018
comment
Круто, это именно то, что я искал. Я понятия не имел о том, чтобы помещать что-то в мой init.py, я думал, что это довольно плохая практика. Большое спасибо. - person Mumrau; 24.01.2018
comment
Некоторые ошибки в архитектуре делают это нефункциональным. В demo/setup.py вы импортируете демонстрационный пакет, которому он принадлежит. - person c24b; 04.12.2019
comment
Какие ошибки были? Вы проверили сопутствующий репозиторий, на который я ссылался. При запуске приложения вам нужно будет не забыть указать PYTHONPATH как путь, содержащий оба пакета (api и demo). Python загружает __init__.py перед запуском demo/main.py. Между прочим, вы также можете извлечь общие ресурсы в отдельный модуль, если считаете, что это лучше. - person Oluwafemi Sule; 04.12.2019