Bagaimana cara mengakses app.config di cetak biru?

114

Saya mencoba mengakses konfigurasi aplikasi akses di dalam cetak biru authorisation.pyyang dalam api paket. Saya menginisialisasi cetak biru __init__.pyyang digunakan dalam authorisation.py.

__init__.py

from flask import Blueprint
api_blueprint = Blueprint("xxx.api", __name__, None)
from api import authorisation

authorisation.py

from flask import request, jsonify, current_app

from ..oauth_adapter import OauthAdapter
from api import api_blueprint as api

client_id = current_app.config.get('CLIENT_ID')
client_secret = current_app.config.get('CLIENT_SECRET')
scope = current_app.config.get('SCOPE')
callback = current_app.config.get('CALLBACK')

auth = OauthAdapter(client_id, client_secret, scope, callback)


@api.route('/authorisation_url')
def authorisation_url():
    url = auth.get_authorisation_url()
    return str(url)

Saya mendapatkan RuntimeError: bekerja di luar konteks aplikasi

Saya mengerti mengapa demikian, tetapi kemudian bagaimana cara yang benar untuk mengakses pengaturan konfigurasi tersebut?

---- Perbarui ---- Untuk sementara, saya telah melakukan ini.

@api.route('/authorisation_url')
def authorisation_url():
    client_id, client_secret, scope, callback = config_helper.get_config()
    auth = OauthAdapter(client_id, client_secret, scope, callback)
    url = auth.get_authorisation_url()
    return str(url)
Chirdeep Tomar
sumber

Jawaban:

133

Gunakan flask.current_appsebagai pengganti appdalam tampilan cetak biru.

from flask import current_app

@api.route("/info")
def get_account_num():
    num = current_app.config["INFO"]

The current_appproxy hanya tersedia dalam konteks permintaan .

Weihuang
sumber
25
Perhatikan bahwa current_appproxy hanya tersedia dalam konteks permintaan.
Sepehr
1
@sephr Ada tips tentang cara mengakses konteks permintaan itu dari tempat lain (tanpa meneruskannya sebagai parameter, tetapi sebagai semacam parameter global)?
carkod
21

recordMetode overloading sepertinya cukup mudah:

api_blueprint = Blueprint('xxx.api',  __name__, None)
api_blueprint.config = {}

@api_blueprint.record
def record_params(setup_state):
  app = setup_state.app
  api_blueprint.config = dict([(key,value) for (key,value) in app.config.iteritems()])
Ashalynd
sumber
1
Untuk Python 3, gunakan: app.config.items () daripada app.config.iteritems ()
DhoTjai
1
Hai, apakah saya perlu memanggil atau mendaftar record_params, saya sudah mencoba tetapi tidak berhasil. Terima kasih banyak.
mrblue
Jika Anda memerlukan akses ke suatu aplikasi (misalnya mendapatkan konfigurasi untuk MENGATUR cetak biru) ini bagus!
Peter Lada
12

Untuk membangun jawaban tbicr , berikut adalah contoh yang menggantikan contoh registermetode :

from flask import Blueprint

auth = None

class RegisteringExampleBlueprint(Blueprint):
    def register(self, app, options, first_registration=False):
        global auth

        config = app.config
        client_id = config.get('CLIENT_ID')
        client_secret = config.get('CLIENT_SECRET')
        scope = config.get('SCOPE')
        callback = config.get('CALLBACK')

        auth = OauthAdapter(client_id, client_secret, scope, callback)

        super(RegisteringExampleBlueprint,
              self).register(app, options, first_registration)

the_blueprint = RegisteringExampleBlueprint('example', __name__)

Dan contoh menggunakan recorddekorator :

from flask import Blueprint
from api import api_blueprint as api

auth = None

# Note there's also a record_once decorator
@api.record
def record_auth(setup_state):
    global auth

    config = setup_state.app.config
    client_id = config.get('CLIENT_ID')
    client_secret = config.get('CLIENT_SECRET')
    scope = config.get('SCOPE')
    callback = config.get('CALLBACK')

    auth = OauthAdapter(client_id, client_secret, scope, callback)
Kyle James Walker
sumber
'@ api.record' tidak bekerja untuk saya,. Dari namespace apa 'api' itu?
Tim Richards
Maaf tidak menyalin itu dari baris dalam pertanyaanfrom api import api_blueprint as api
Kyle James Walker
7

Cetak biru memiliki registermetode yang dipanggil saat Anda mendaftar cetak biru . Jadi, Anda dapat mengganti metode ini atau menggunakan recorddekorator untuk mendeskripsikan logika yang bergantung padanya app.

tbicr
sumber
4

The current_apppendekatan baik-baik saja tetapi Anda harus memiliki beberapa konteks permintaan. Jika Anda tidak memilikinya (beberapa pekerjaan awal seperti pengujian, misalnya) sebaiknya Anda menempatkannya

with app.test_request_context('/'):

sebelum current_apppanggilan ini .

Anda akan memiliki RuntimeError: working outside of application context, sebagai gantinya.

Ben Usman
sumber
3
Bagaimana dengan saat aplikasi dibuat di pabrik dan oleh karena itu 'app' (atau apa pun yang disebut aplikasi flask) tidak tersedia untuk diimpor? Permintaan di dalam tidak masalah karena selama permintaan ada konteks aplikasi, tetapi ketika mendefinisikan bagian di luar logika permintaan yang memerlukan konfigurasi aplikasi. bagaimana seseorang bisa mengakses konfigurasi aplikasi jika Anda tidak dapat menggunakan aplikasi untuk membuat konteks?
RobertoCuba
3

Anda juga perlu mengimpor appvariabel utama (atau apa pun yang Anda sebut itu) yang dikembalikan oleh Flask():

from someplace import app
app.config.get('CLIENT_ID')

Atau lakukan itu dari dalam permintaan:

@api.route('/authorisation_url')
def authorisation_url():
    client_id = current_app.config.get('CLIENT_ID')
    url = auth.get_authorisation_url()
    return str(url)
Daniel Chatfield
sumber
4
Ya, saya tidak ingin melakukan salah satu dari keduanya. Pertama membuat referensi silang dan pendekatan kedua tidak KERING.
Chirdeep Tomar
2
@ChirdeepTomar Jika pendekatan pertama adalah membuat impor melingkar (yang merusak aplikasi), maka ada yang salah dengan struktur aplikasi Anda.
Daniel Chatfield
13
@DanielChatfield itu tidak benar. Objek aplikasi adalah objek yang mendaftarkan cetak biru. Menyarankan bahwa itu benar untuk cetak biru kemudian mengimpor objek aplikasi akan selalu menyebabkan ketergantungan melingkar. Lihat jawaban lain untuk strategi yang benar.
sholsapp
@sholsapp Saya tahu ini akan membuat impor melingkar (seperti yang terjadi di flask docs: flask.pocoo.org/docs/patterns/packages ), saya katakan jika itu membuat impor melingkar yang merusak aplikasi .
Daniel Chatfield
1

Anda juga bisa membungkus cetak biru dalam sebuah fungsi dan meneruskan appsebagai argumen:

Cetak biru:

def get_blueprint(app):
    bp = Blueprint()
    return bp

Utama:

from . import my_blueprint
app.register_blueprint(my_blueprint.get_blueprint(app))
Georg Schölly
sumber
Saya mencoba ini, tetapi saya mendapat "Kesalahan Server Internal".
MD004
Adakah kelemahan dengan pendekatan ini?
Tuukka Mustonen
@Tuukka: Saya tidak ingat kekurangan tertentu, sudah terlalu lama sejak saya menggunakannya. Mungkin ada beberapa keuntungan menggunakan flask.current_appsaat Anda menggunakan cetak biru di beberapa aplikasi. Saya akan menyarankan jika pendekatan ini menyelesaikan masalah Anda untuk menggunakannya, Flask tidak menerapkan pendekatan khusus.
Georg Schölly