Kapan sebaiknya Flask.g digunakan?


174

Saya melihat bahwa gakan berpindah dari konteks permintaan ke konteks aplikasi di Flask 0.10, yang membuat saya bingung tentang tujuan penggunaan g.

Pemahaman saya (untuk Flask 0.9) adalah bahwa:

  • g tinggal dalam konteks permintaan, yaitu, dibuat baru ketika permintaan dimulai, dan tersedia hingga berakhir
  • gdimaksudkan untuk digunakan sebagai "papan tulis permintaan", di mana saya dapat menaruh barang-barang yang relevan selama durasi permintaan (yaitu, menetapkan bendera di awal permintaan dan menanganinya di akhir, mungkin dari a before_request/ after_requestpair)
  • selain memegang status tingkat permintaan, gdapat dan harus digunakan untuk manajemen sumber daya, yaitu, memegang koneksi basis data, dll.

Manakah dari kalimat-kalimat ini yang tidak lagi benar dalam Flask 0.10? Bisakah seseorang mengarahkan saya ke sumber yang membahas alasan perubahan itu? Apa yang harus saya gunakan sebagai "papan tulis permintaan" di Flask 0.10 - haruskah saya membuat aplikasi sendiri / proxy lokal thread-ekstensi spesifik saya dan mendorongnya ke tumpukan konteks before_request? Apa gunanya manajemen sumber daya pada konteks aplikasi, jika aplikasi saya hidup untuk waktu yang lama (tidak seperti permintaan) dan dengan demikian sumber daya tidak pernah dibebaskan?


Saya setuju, itu adalah perubahan yang cukup aneh. Semoga mitsuhiko mengimplementasikan semacam objek konteks permintaan untuk menggantikan gdi 0,10, kalau tidak sepertinya banyak kode mungkin mulai mengembangkan beberapa bug yang licik.
Anorov

11
FWIW, Armin Ronacher (penulis Flask) telah merilis sekuel "Advanced Flask Patterns" yang menunjukkan beberapa contoh kode tentang cara menggunakan yang baru flask.g. speakerdeck.com/mitsuhiko/advanced-flask-patterns-1
Markus Unterwaditzer

1
juga konteks permintaan baru menyiratkan konteks aplikasi baru, jadi seharusnya hanya berfungsi dengan baik dalam penggunaan normal
Ronny

Jawaban:


120

Pola Labu Lanjutan , seperti yang ditautkan oleh Markus , menjelaskan beberapa perubahan gpada 0.10:

  • g sekarang tinggal dalam konteks aplikasi.
  • Setiap permintaan mendorong konteks aplikasi baru , menghapus yang lama, sehingga gmasih dapat digunakan untuk mengatur flag per-request tanpa mengubah kode.
  • Konteks aplikasi muncul setelah teardown_request dipanggil. (Presentasi Armin menjelaskan ini karena hal-hal seperti membuat koneksi DB adalah tugas yang mengatur lingkungan untuk permintaan, dan tidak boleh ditangani di dalam before_requestdan after_request)

Dalam kode sumber yang Anda tautkan, kapankah app_ctx is None or app_ctx.app != self.appFalse, konteks aplikasi lama tampaknya digunakan kembali? Ini sepertinya tidak benar, karena konteks aplikasi "tidak akan dibagikan di antara permintaan" ...
nalzok

2
Apakah Anda mengacu pada mendorongapp.app_context() ? Jika demikian, harus dicatat app_context()instantiates konteks aplikasi baru setiap panggilan - itu tidak pernah menggunakan kembali konteks.
theY4Kman

1
Ya itu benar, tetapi ketika app_ctx is not None and app_ctx.app == self.app, app_ctx = self.app.app_context()garis tidak dieksekusi; hanya self._implicit_app_ctx_stack.append(None)dieksekusi dalam kasus ini.
nalzok

1
Oh, maaf, saya salah baca! Dalam pengaturan produksi, hanya ada satu permintaan yang dilayani per utas (atau greenlet). Hanya satu RequestContextyang didorong, jadi hanya satu AppContextyang didorong. Tetapi jika mode debug aktif dan permintaan gagal, Flask menyimpan konteksnya , sehingga dapat digunakan dengan debugger . Noneditambahkan ke _app_ctx_stack, jadi ketika permintaan sedang dirobohkan, ia tahu belum muncul AppContextdulu. Hal yang sama terjadi dengan klien uji, yang mempertahankan konteksnya, sehingga dapat diperiksa.
theY4Kman

Jadi ruang lingkup g adalah per permintaan (utas) dan itu tidak akan mempertahankan nilai dalam permintaan berikutnya.
variabel

83

Sebagai tambahan pada informasi di utas ini: Saya agak bingung dengan perilaku flask.gjuga, tetapi beberapa pengujian cepat telah membantu saya untuk mengklarifikasi hal itu. Inilah yang saya coba:

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

    with app.test_request_context():
        print('in first request context')
        print('g.foo should be abc, is: {0}'.format(g.foo))
        print('setting g.foo to xyz')
        g.foo = 'xyz'
        print('g.foo should be xyz, is: {0}'.format(g.foo))

    print('in app context, after first request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))

    with app.test_request_context():
        print('in second request context')
        print('g.foo should be abc, is: {0}'.format(g.foo))
        print('setting g.foo to pqr')
        g.foo = 'pqr'
        print('g.foo should be pqr, is: {0}'.format(g.foo))

    print('in app context, after second request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))

Dan inilah output yang diberikannya:

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be abc, is: abc
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in app context, after first request context
g.foo should be abc, is: xyz  

in second request context
g.foo should be abc, is: xyz
setting g.foo to pqr
g.foo should be pqr, is: pqr  

in app context, after second request context
g.foo should be abc, is: pqr

Seperti kata Y4Kman di atas, "Setiap permintaan mendorong konteks aplikasi baru". Dan seperti yang dikatakan oleh Flask , konteks aplikasi "tidak akan dibagikan di antara permintaan". Sekarang, apa yang belum dinyatakan secara eksplisit (meskipun saya kira itu tersirat dari pernyataan ini), dan apa yang ditunjukkan oleh pengujian saya, adalah bahwa Anda tidak boleh secara eksplisit membuat beberapa konteks permintaan yang bersarang di dalam satu konteks aplikasi, karena flask.g(dan co) tidak tidak memiliki keajaiban yang berfungsi dalam dua "level" konteks yang berbeda, dengan status berbeda yang ada secara independen di level aplikasi dan permintaan.

Kenyataannya adalah bahwa "aplikasi konteks" berpotensi cukup nama menyesatkan, karena app.app_context() merupakan suatu konteks per-permintaan , persis sama dengan "permintaan konteks" . Anggap saja sebagai "lite konteks permintaan", hanya diperlukan dalam kasus di mana Anda memerlukan beberapa variabel yang biasanya memerlukan konteks permintaan, tetapi Anda tidak memerlukan akses ke objek permintaan apa pun (misalnya ketika menjalankan operasi batch DB dalam skrip shell). Jika Anda mencoba dan memperluas konteks aplikasi untuk mencakup lebih dari satu konteks permintaan, Anda meminta masalah. Jadi, daripada pengujian saya di atas, Anda sebaiknya menulis kode seperti ini dengan konteks Flask:

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in first request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to xyz')
    g.foo = 'xyz'
    print('g.foo should be xyz, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in second request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to pqr')
    g.foo = 'pqr'
    print('g.foo should be pqr, is: {0}'.format(g.foo))

Yang akan memberikan hasil yang diharapkan:

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be None, is: None
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in second request context
g.foo should be None, is: None
setting g.foo to pqr
g.foo should be pqr, is: pqr

7
Terpilih karena paragraf terakhir, konteks labu cukup membingungkan untuk dipahami pada awalnya. Dari namanya, Anda merasa bahwa konteks permintaan sesuai permintaan dan bahwa konteks aplikasi ada bahkan setelah permintaan atau tidak terpengaruh oleh masa pakai itu.
simanacci
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.