Flask.g ne zaman kullanılmalıdır?


174

Ben testereg beni yapılmış Flask 0.10 konusu uygulama kapsamında isteği bağlamdan hareket edecek, amaçlanan kullanımı hakkında karıştıg .

Anlayışım (Flask 0.9 için):

  • g istek bağlamında yaşıyor, yani istekler başladığında yeniden oluşturuldu ve bitene kadar kullanılabilir
  • g"istek tahtası" olarak kullanılmak üzere tasarlanmıştır, burada istek süresince alakalı şeyler koyabilirim (yani, isteğin başına bir bayrak koyabilir ve sonunda, muhtemelen bir before_request/after_request çiftinden kaldırabilirim)
  • istek düzeyinde durumu tutmanın yanı sıra, gkaynak yönetimi, yani veritabanı bağlantılarını tutma vb. için de kullanılabilir ve kullanılmalıdır.

Bu cümlelerden hangisi artık Flask 0.10'da geçerli değil? Birisi beni değişikliğin nedenlerini tartışan bir kaynağa yönlendirebilir mi? Flask 0.10 bir "istek karatahta" olarak ne kullanmalıyım - kendi app / uzantıya özel evre yerel proxy oluşturmak ve bağlam yığınına itmek gerekir before_request? Uygulamam uzun bir süre yaşıyorsa (istek gibi değil) ve dolayısıyla kaynaklar asla serbest bırakılmazsa, uygulama bağlamında kaynak yönetiminin anlamı nedir?


Katılıyorum, bu oldukça garip bir değişiklik. Umarım mitsuhiko g0.10 içinde değiştirmek için bir çeşit istek bağlam nesnesi uygular , aksi takdirde bir sürü kod bazı sapkın hatalar geliştirmeye başlayabilir gibi geliyor.
Anorov

11
FWIW, Armin Ronacher (Flask'ın yazarı), yenisinin nasıl kullanılacağına dair bazı örnek kod gösteren "Gelişmiş Flask Desenleri" nin bir devamı yayınladı flask.g. speakerdeck.com/mitsuhiko/advanced-flask-patterns-1
Markus Unterwaditzer

1
ayrıca yeni bir istek bağlamı yeni bir uygulama bağlamı anlamına gelir, bu yüzden normal kullanımda iyi çalışmalıdır
Ronny

Yanıtlar:


120

Markus ile bağlantılı olarak Gelişmiş Flask Desenleri , 0.10'daki değişikliklerin bazılarını açıklıyor g:

  • g şimdi uygulama bağlamında yaşıyor.
  • Her istek yeni bir uygulama bağlamını zorlar , eskisini siler,g kodda değişiklik yapmadan istek başına bayrak ayarlamak için kullanılabilir.
  • Uygulama bağlamı çağrıldıktan sonra açılır teardown_request. (Armin'in sunumu, bunun nedeni, DB bağlantıları oluşturmak gibi şeylerin , istek için ortamı ayarlayan ve içinde before_requestve içinde ele alınmaması gereken görevlerdir after_request)

Bağlandığınız kaynak kodunda app_ctx is None or app_ctx.app != self.app, False ne zaman eski uygulama içeriği yeniden kullanılıyor gibi görünüyor? Uygulama içeriği "istekler arasında paylaşılmayacak" için bu doğru görünmüyor ...
nalzok

2
İtmeye mi atıfta bulunuyorsunuzapp.app_context() ? Öyleyse, app_context()her çağrıda yeni bir uygulama bağlamı oluşturduğuna dikkat edilmelidir - asla bir bağlamı yeniden kullanmaz.
theY4Kman

1
Evet bu doğru, ama ne zaman app_ctx is not None and app_ctx.app == self.app, app_ctx = self.app.app_context()çizgi edilir değil yürütülen; yalnızca self._implicit_app_ctx_stack.append(None)bu durumda yürütülür.
nalzok

1
Üzgünüm, yanlış okudum! Üretim ortamında, iş parçacığı (veya broşür) için yalnızca bir istek sunulur. Sadece biri RequestContextitilir, sadece biri AppContextitilir. Ancak hata ayıklama modu açıksa ve bir istek başarısız olursa, Flask bağlamı kaydeder , böylece hata ayıklayıcı ile kullanılabilir . Noneeklenir _app_ctx_stack, bu nedenle istek yırtıldığında AppContexthenüz patlamamayı bilir . Aynı şey, bağlamı koruyan test istemcisi için de geçerlidir, böylece denetlenebilir.
theY4Kman

Dolayısıyla g kapsamı istek başınadır (iş parçacığı) ve sonraki istekte bu değeri korumaz.
değişken

83

Bu konudaki bilgilere bir ek olarak: Davranışımla biraz karıştım flask.g, ancak bazı hızlı testler netleştirmeme yardımcı oldu. İşte ne denedim:

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))

Ve işte verdiği çıktı:

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

Y4Kman'ın yukarıda söylediği gibi, "Her istek yeni bir uygulama bağlamı getirir". Ve Flask dokümanlarının dediği gibi, uygulama içeriği "istekler arasında paylaşılmayacak". Şimdi, açıkça ifade edilmemiş olan şey (bu ifadelerden ima edildiğine rağmen) ve testimin açıkça gösterdiği şey, hiçbir zaman açıkça bir uygulama bağlamı içinde iç içe birden fazla istek bağlamı oluşturmamanızdır, çünküflask.g (ve co) • farklı durumların uygulama ve talep seviyelerinde bağımsız olarak mevcut olduğu, bağlamın iki farklı "seviyesinde" işlev gördüğü herhangi bir sihire sahip olmak.

Çünkü gerçeklik, yani "uygulama bağlamı" potansiyel olarak oldukça yanıltıcı adıdır app.app_context() olan bir istek başına bağlam tamamen aynı, "istek bağlamında" . Bunu, yalnızca normalde bir istek bağlamı gerektiren bazı değişkenlere ihtiyacınız olduğunda gerekli olan ancak herhangi bir istek nesnesine (örneğin bir toplu iş DB kabuk betiği). Uygulama bağlamını birden fazla istek bağlamını kapsayacak şekilde genişletmeye çalışırsanız, sorun istiyorsunuz demektir. Yani, yukarıdaki testim yerine, Flask'ın bağlamlarıyla bunun gibi bir kod yazmalısınız:

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))

Bu beklenen sonuçları verecektir:

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
Son paragraf nedeniyle, şişenin bağlamları ilk başta anlaşılması oldukça kafa karıştırıcıdır. Addan, istek bağlamının istek başına olduğunu ve uygulama bağlamının bir istekten sonra bile var olduğunu veya yaşam süresinden etkilenmediğini hissedersiniz.
simanacci
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.