【问题标题】:How can I load Jinja2 templates dynamically from Google Cloud Storage in App Engine?如何从 App Engine 中的 Google Cloud Storage 动态加载 Jinja2 模板?
【发布时间】:2019-02-09 23:35:52
【问题描述】:

我在 App Engine 上有一个应用程序,并希望以一种无需重新部署整个应用程序的方式动态更新它们的方式部署我的 Jinja2 模板。

理想情况下,它们将存储在 Google Cloud Storage 中,这样我就可以只替换存储桶中的模板文件并让实时应用程序立即使用它们。但是,Flask 似乎要求模板是应用程序本地的。

这可能吗?

【问题讨论】:

  • 您可以开发自己的 Jinja 模板加载器来加载来自不同来源的模板。但是您的“实时应用程序立即使用”并不那么容易,因为模板被缓存了。

标签: python google-app-engine flask google-cloud-platform jinja2


【解决方案1】:

这可以通过直接从 Google Cloud Storage 为每个请求加载每个模板,并使用 Flask 中的 render_template_string 函数来实现。

例如,如果您的模板文件 hello.html 如下所示:

<h1>Hello {{ name }}!</h1>

将 Google Cloud Storage 资源添加到您的应用程序,创建一个新存储桶(我们称之为 your-bucket),然后将此文件上传到存储桶。

在你的requirements.txt:

flask
google-cloud-storage

在你的main.py:

from flask import Flask, render_template_string
from google.cloud import storage

app = Flask(__name__)

# Initialize the bucket you created containing the templates
bucket = storage.Client().bucket('your-bucket')

@app.route('/')
def hello():
    # Load the template string from Cloud Storage
    template_string = bucket.blob('hello.html').download_as_string().decode('ascii')

    # Now use render_template_string the same way you'd use render_template
    return render_template_string(template_string, name='World')

请注意,由于此应用程序会为每个请求重新下载模板,因此对于高流量应用程序,它可能会产生大量额外的请求时间和成本。

因此,最好以某种方式“缓存”模板字符串(例如,通过Cloud Memorystore),然后使用Object Change Notification(可能通过Google Cloud Function trigger)来确定何时存储桶中的文件已更改,并更新缓存。

【讨论】:

    【解决方案2】:

    这是一个很好的 Flask render_template() 调用的包装器来实现这一点

    • 1) 从 URL 加载静态文件,传递参数
    • 2) 或将文件名和参数传递给常规 Flask render_template 方法。

    然后您可以将 /templates 文件复制到您的 Google CDN 并引用公共 URL

    -

    from flask import Flask, render_template, render_template_string
    
    
    def renderTemplateLocalOrRemote(file, **kwargs): 
         if REMOTE_LOADING_ENABLED is defined: # Load the template file remotely
             r = requests.get('https://'+YOUR_BASE_URL+"/templates/"+file)
             template_string = r.content.decode('utf-8')
             return render_template_string(template_string, **kwargs)
         else: # Load the template file from local, pass on to standard method
             return render_template(file, **kwargs)
    

    然后你可以在任何你使用 flask.render_template() 的地方使用这个包装器

    @app.route('/')
    def hello():
        return renderTemplateLocalOrRemote('hello.html', name='lalala', another_param='lilili')
    
    @app.route('/another_route')
    def hello2():
        return renderTemplateLocalOrRemote('hello2.html', different_param='lilili')
    

    并使用打开/关闭它

    REMOTE_LOADING_ENABLED
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-22
      • 2012-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-01
      • 2015-07-07
      • 1970-01-01
      相关资源
      最近更新 更多