Khi nào nên sử dụng Flask.g?


173

Tôi thấy điều đó gsẽ chuyển từ bối cảnh yêu cầu sang bối cảnh ứng dụng trong Flask 0.10, điều này khiến tôi bối rối về mục đích sử dụng g.

Sự hiểu biết của tôi (đối với Flask 0.9) là:

  • g sống trong bối cảnh yêu cầu, nghĩa là, được tạo ra một lần nữa khi các yêu cầu bắt đầu và có sẵn cho đến khi nó kết thúc
  • gđược dự định sẽ được sử dụng như một "bảng đen yêu cầu", trong đó tôi có thể đặt các nội dung có liên quan trong thời gian yêu cầu (nghĩa là đặt cờ ở đầu yêu cầu và xử lý ở cuối, có thể từ một before_request/ after_requestcặp)
  • ngoài việc giữ trạng thái mức yêu cầu, gcó thể và nên được sử dụng để quản lý tài nguyên, nghĩa là giữ các kết nối cơ sở dữ liệu, v.v.

Câu nào trong số những câu này không còn đúng trong Flask 0.10? Ai đó có thể chỉ cho tôi một tài nguyên thảo luận về lý do của sự thay đổi không? Tôi nên sử dụng làm "bảng đen yêu cầu" trong Flask 0.10 - tôi có nên tạo proxy cục bộ của ứng dụng / tiện ích mở rộng cụ thể của riêng mình và đẩy nó vào ngăn xếp ngữ cảnh before_requestkhông? Quan điểm của quản lý tài nguyên trong bối cảnh ứng dụng là gì, nếu ứng dụng của tôi tồn tại trong một thời gian dài (không giống như một yêu cầu) và do đó, các tài nguyên không bao giờ được giải phóng?


Tôi đồng ý, đó là một thay đổi khá kỳ lạ. Hy vọng rằng mitsuhiko triển khai một số loại đối tượng bối cảnh yêu cầu để thay thế gtrong 0.10, nếu không, có vẻ như rất nhiều mã có thể bắt đầu phát triển một số lỗi sai.
Anorov

11
FWIW, Armin Ronacher (tác giả của Flask) đã phát hành phần tiếp theo của "Các mẫu bình nâng cao" cho thấy một số mã ví dụ về cách sử dụng cái mới flask.g. loadeck.com/mitsuhiko/advified-flask-potypes-1
Markus Unterwaditzer

1
cũng là bối cảnh yêu cầu mới ngụ ý bối cảnh ứng dụng mới, vì vậy nó sẽ hoạt động tốt trong sử dụng bình thường
Ronny

Câu trả lời:


119

Các mẫu bình nâng cao , được liên kết bởi Markus , giải thích một số thay đổi gtrong 0.10:

  • g bây giờ sống trong bối cảnh ứng dụng.
  • Mỗi yêu cầu đẩy một bối cảnh ứng dụng mới , xóa sạch bối cảnh cũ, do đó gvẫn có thể được sử dụng để đặt cờ cho mỗi yêu cầu mà không thay đổi mã.
  • Bối cảnh ứng dụng được bật lên sau khi teardown_request được gọi. (Bản trình bày của Armin giải thích điều này là do những thứ như tạo kết nối DB là các tác vụ thiết lập môi trường cho yêu cầu và không nên được xử lý bên trong before_requestafter_request)

Trong mã nguồn bạn liên kết đến, khi nào app_ctx is None or app_ctx.app != self.applà Sai, bối cảnh ứng dụng cũ dường như được sử dụng lại? Điều này dường như không đúng, vì bối cảnh ứng dụng "sẽ không được chia sẻ giữa các yêu cầu" ...
nalzok 18/07/17

2
Bạn đang đề cập đến việc đẩyapp.app_context() ? Nếu vậy, cần lưu ý ngay lập tức app_context()một bối cảnh ứng dụng mới mỗi cuộc gọi - nó không bao giờ sử dụng lại một bối cảnh.
theY4Kman

1
Đúng, nhưng khi đó app_ctx is not None and app_ctx.app == self.app, app_ctx = self.app.app_context()dòng không được thực thi; chỉ self._implicit_app_ctx_stack.append(None)được thực hiện trong trường hợp này.
nalzok

1
Ôi xin lỗi, tôi đọc nhầm! Trong cài đặt sản xuất, chỉ có một yêu cầu được phục vụ cho mỗi luồng (hoặc greenlet). Chỉ có một RequestContextđược đẩy, vì vậy chỉ có một AppContextđược đẩy. Nhưng nếu chế độ gỡ lỗi được bật và yêu cầu không thành công, Flask sẽ lưu bối cảnh , vì vậy nó có thể được sử dụng với trình gỡ lỗi . Noneđược gắn vào _app_ctx_stack, vì vậy khi yêu cầu bị phá bỏ, nó biết chưa bật lên AppContext. Điều tương tự xảy ra với máy khách thử nghiệm, vẫn giữ bối cảnh, vì vậy nó có thể được kiểm tra.
theY4Kman

Vì vậy, phạm vi của g là trên mỗi yêu cầu (luồng) và nó sẽ không giữ lại giá trị trong yêu cầu tiếp theo.
biến

83

Là một phụ lục cho thông tin trong chủ đề này: Tôi đã hơi bối rối bởi hành vi của flask.gquá, nhưng một số thử nghiệm nhanh đã giúp tôi làm rõ nó. Đây là những gì tôi đã thử:

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

Và đây là đầu ra mà nó mang lại:

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

NhưY4Kman đã nói ở trên, "Mọi yêu cầu đều đẩy một bối cảnh ứng dụng mới". Và như các tài liệu Flask nói , bối cảnh ứng dụng "sẽ không được chia sẻ giữa các yêu cầu". Bây giờ, điều chưa được tuyên bố rõ ràng (mặc dù tôi đoán nó được ngụ ý từ các tuyên bố này) và điều mà thử nghiệm của tôi cho thấy rõ, là bạn không bao giờ nên tạo ra nhiều bối cảnh yêu cầu được lồng trong một bối cảnh ứng dụng, bởi vì flask.g(và đồng) không ' t có bất kỳ phép thuật nào theo đó nó hoạt động trong hai "cấp độ" bối cảnh khác nhau, với các trạng thái khác nhau tồn tại độc lập ở cấp độ ứng dụng và yêu cầu.

Thực tế là "bối cảnh ứng dụng" có khả năng là một cái tên dễ gây hiểu lầm, bởi vì đó app.app_context() một bối cảnh theo yêu cầu , giống hệt như "bối cảnh yêu cầu" . Hãy nghĩ về nó như một "lite bối cảnh yêu cầu", chỉ được yêu cầu trong trường hợp bạn cần một số biến thường yêu cầu bối cảnh yêu cầu, nhưng bạn không cần truy cập vào bất kỳ đối tượng yêu cầu nào (ví dụ: khi chạy các hoạt động DB hàng loạt trong một kịch bản shell). Nếu bạn cố gắng và mở rộng bối cảnh ứng dụng để bao gồm nhiều hơn một bối cảnh yêu cầu, bạn sẽ gặp rắc rối. Vì vậy, thay vì thử nghiệm của tôi ở trên, thay vào đó, bạn nên viết mã như thế này với bối cảnh của 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))

Điều này sẽ cho kết quả mong đợi:

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
Được nâng cấp vì đoạn cuối, bối cảnh của bình khá khó hiểu lúc đầu. Từ tên, bạn có cảm giác bối cảnh yêu cầu là theo yêu cầu và bối cảnh ứng dụng tồn tại ngay cả sau khi yêu cầu hoặc không bị ảnh hưởng bởi thời gian tồn tại của nó.
simanacci
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.