Python 在appengine中为jinja2配置自动重新加载模板并启用字节码缓存

Python 在appengine中为jinja2配置自动重新加载模板并启用字节码缓存,python,google-app-engine,jinja2,Python,Google App Engine,Jinja2,如何在Appengine中将jinja2配置为: 更新模板时自动重新加载 启用字节码缓存,以便在每个实例之间共享。我更喜欢jinja2在编译模板时生成字节码,并将其存储到数据存储中。所以下一个实例将加载字节码,而不是重复编译模板 几个星期以来我一直在寻找解决办法。最后我终于明白了,我想和大家分享我的代码。我的代码中有4个python源文件 TemplateEngine.py、ContentRenderer.py、TestContent.py和Update\u Template.py 文件:Tem

如何在Appengine中将jinja2配置为:

  • 更新模板时自动重新加载
  • 启用字节码缓存,以便在每个实例之间共享。我更喜欢jinja2在编译模板时生成字节码,并将其存储到数据存储中。所以下一个实例将加载字节码,而不是重复编译模板

  • 几个星期以来我一直在寻找解决办法。最后我终于明白了,我想和大家分享我的代码。我的代码中有4个python源文件

    TemplateEngine.py、ContentRenderer.py、TestContent.py和Update\u Template.py

    文件:TemplateEngine.py

    注:

    我使用now=datetime.utcnow()+timedelta(小时=8),因为我的时区是GMT+8

    必须使用ndb.BlobProperty来存储字节码,ndb.TextProperty将不起作用

    from google.appengine.ext import ndb
    from datetime import datetime,timedelta
    
    class SiteTemplates(ndb.Model):
      name = ndb.StringProperty(indexed=True, required=True)
      data = ndb.TextProperty()
      uptodate = ndb.BooleanProperty(required=True)
    
    class SiteTemplateBytecodes(ndb.Model):
      key = ndb.StringProperty(indexed=True, required=True)
      data = ndb.BlobProperty(required=True)
      mod_datetime = ndb.DateTimeProperty(required=True)
    
    class LocalCache(jinja2.BytecodeCache):
    
      def load_bytecode(self, bucket):
        q = SiteTemplateBytecodes.query(SiteTemplateBytecodes.key == bucket.key)
        if q.count() > 0:
          r = q.get()
          bucket.bytecode_from_string(r.data)
    
      def dump_bytecode(self, bucket):
        now = datetime.utcnow() + timedelta(hours=8)
        q = SiteTemplateBytecodes.query(SiteTemplateBytecodes.key == bucket.key)
        if q.count() > 0:
          r = q.get()
          r.data = bucket.bytecode_to_string()
          r.mod_datetime = now
        else:
          r = SiteTemplateBytecodes(key=bucket.key, data=bucket.bytecode_to_string(), mod_datetime=now)
        r.put()
    
    def Update_Template_Source(tn, source):
      try:
        q = SiteTemplates.query(SiteTemplates.name == tn)
        if q.count() == 0:
          u = mkiniTemplates(name=tn, data=source, uptodate=False)
        else:
          u = q.get()
          u.name=tn
          u.data=source
          u.uptodate=False
        u.put()
        return True
      except Exception,e:
        logging.exception(e)
        return False
    
    def Get_Template_Source(tn):
      uptodate = False
    
      def Template_Uptodate():
        return uptodate
    
      try:
        q = SiteTemplates.query(SiteTemplates.name == tn)
        if q.count() > 0:
          r = q.get()
          uptodate = r.uptodate
    
          if r.uptodate == False:
            r.uptodate=True
            r.put()
    
          return r.data, tn, Template_Uptodate
        else:
          return None
      except Exception,e:
        logging.exception(e)
        return None
    
    文件:ContentRenderer.py

    注意:设置缓存_size=0非常重要,否则字节码缓存功能将被禁用。我不知道为什么

    from TemplateEngine import Get_Template_Source
    import jinja2 
    
    def Render(tn,tags):
      global te
      return te.Render(tn, tags)
    
    bcc = LocalCache()
    te = jinja2.Environment(loader=jinja2.FunctionLoader(Get_Template_Source), cache_size=0, extensions=['jinja2.ext.autoescape'], bytecode_cache=bcc)
    
    文件:更新模板.py

    注意:使用更新模板源()将模板源更新到数据存储

    from TemplateEngine import Update_Template_Source
    template_source = '<html><body>hello word to {{title}}!</body></html>'
    if Update_Template_Source('my-template.html', template_source):
      print 'template is updated'
    else:
      print 'error when updating template source'
    

    您将意识到,即使您的应用程序中有20多个实例,延迟时间也不会增加,即使您更新了模板。模板源代码将在5到10秒内更新。

    我已经找了几个星期的解决方案了。最后我终于明白了,我想和大家分享我的代码。我的代码中有4个python源文件

    TemplateEngine.py、ContentRenderer.py、TestContent.py和Update\u Template.py

    文件:TemplateEngine.py

    注:

    我使用now=datetime.utcnow()+timedelta(小时=8),因为我的时区是GMT+8

    必须使用ndb.BlobProperty来存储字节码,ndb.TextProperty将不起作用

    from google.appengine.ext import ndb
    from datetime import datetime,timedelta
    
    class SiteTemplates(ndb.Model):
      name = ndb.StringProperty(indexed=True, required=True)
      data = ndb.TextProperty()
      uptodate = ndb.BooleanProperty(required=True)
    
    class SiteTemplateBytecodes(ndb.Model):
      key = ndb.StringProperty(indexed=True, required=True)
      data = ndb.BlobProperty(required=True)
      mod_datetime = ndb.DateTimeProperty(required=True)
    
    class LocalCache(jinja2.BytecodeCache):
    
      def load_bytecode(self, bucket):
        q = SiteTemplateBytecodes.query(SiteTemplateBytecodes.key == bucket.key)
        if q.count() > 0:
          r = q.get()
          bucket.bytecode_from_string(r.data)
    
      def dump_bytecode(self, bucket):
        now = datetime.utcnow() + timedelta(hours=8)
        q = SiteTemplateBytecodes.query(SiteTemplateBytecodes.key == bucket.key)
        if q.count() > 0:
          r = q.get()
          r.data = bucket.bytecode_to_string()
          r.mod_datetime = now
        else:
          r = SiteTemplateBytecodes(key=bucket.key, data=bucket.bytecode_to_string(), mod_datetime=now)
        r.put()
    
    def Update_Template_Source(tn, source):
      try:
        q = SiteTemplates.query(SiteTemplates.name == tn)
        if q.count() == 0:
          u = mkiniTemplates(name=tn, data=source, uptodate=False)
        else:
          u = q.get()
          u.name=tn
          u.data=source
          u.uptodate=False
        u.put()
        return True
      except Exception,e:
        logging.exception(e)
        return False
    
    def Get_Template_Source(tn):
      uptodate = False
    
      def Template_Uptodate():
        return uptodate
    
      try:
        q = SiteTemplates.query(SiteTemplates.name == tn)
        if q.count() > 0:
          r = q.get()
          uptodate = r.uptodate
    
          if r.uptodate == False:
            r.uptodate=True
            r.put()
    
          return r.data, tn, Template_Uptodate
        else:
          return None
      except Exception,e:
        logging.exception(e)
        return None
    
    文件:ContentRenderer.py

    注意:设置缓存_size=0非常重要,否则字节码缓存功能将被禁用。我不知道为什么

    from TemplateEngine import Get_Template_Source
    import jinja2 
    
    def Render(tn,tags):
      global te
      return te.Render(tn, tags)
    
    bcc = LocalCache()
    te = jinja2.Environment(loader=jinja2.FunctionLoader(Get_Template_Source), cache_size=0, extensions=['jinja2.ext.autoescape'], bytecode_cache=bcc)
    
    文件:更新模板.py

    注意:使用更新模板源()将模板源更新到数据存储

    from TemplateEngine import Update_Template_Source
    template_source = '<html><body>hello word to {{title}}!</body></html>'
    if Update_Template_Source('my-template.html', template_source):
      print 'template is updated'
    else:
      print 'error when updating template source'
    

    您将意识到,即使您的应用程序中有20多个实例,延迟时间也不会增加,即使您更新了模板。模板源将在5到10秒内更新。

    我使用app engine memcache Client()添加了bcc,如下所示:

    我的函数加载器:

    def html(self, cid):
    
        def _html_txt_up_to_date():  # closure to check if template is up to date
    
            return CMSUpdates.check_no_update(cid, template.modified)
    
        template = ndb.Key('Templates', cid, parent=self.parent_key).get()
        if not template:
            logging.error('DynLoader (HTML/TXT): %s' % cid)
            return None              # raises TemplateNotFound exception
    
        return template.content, None, _html_txt_up_to_date
    
    模板模型使用template.modified:ndb.DateTimeProperty(auto\u now=True)

    关闭功能:

    class CMSUpdates(ndb.Model):                                                                        
        updates = ndb.JsonProperty()
    
        @classmethod
        def check_no_update(cls, cid, cid_modified):                                                      
    
            cms_updates = cls.get_or_insert('cms_updates', updates=dict()).updates
            if cid in cms_updates:   # cid modified has dt microseconds
                if cid_modified >= datetime.strptime(cms_updates[cid], '%Y-%m-%d %H:%M:%S'):
                    if (datetime.now() - timedelta(days=1)) > cid_modified:
                        del cms_updates[cid]
                        cls(id='cms_updates', updates=cms_updates).put_async()
                    return True
                return False         # reload the template
            return True                    
    

    我使用appengine memcache Client()添加了bcc,如下所示:

    我的函数加载器:

    def html(self, cid):
    
        def _html_txt_up_to_date():  # closure to check if template is up to date
    
            return CMSUpdates.check_no_update(cid, template.modified)
    
        template = ndb.Key('Templates', cid, parent=self.parent_key).get()
        if not template:
            logging.error('DynLoader (HTML/TXT): %s' % cid)
            return None              # raises TemplateNotFound exception
    
        return template.content, None, _html_txt_up_to_date
    
    模板模型使用template.modified:ndb.DateTimeProperty(auto\u now=True)

    关闭功能:

    class CMSUpdates(ndb.Model):                                                                        
        updates = ndb.JsonProperty()
    
        @classmethod
        def check_no_update(cls, cid, cid_modified):                                                      
    
            cms_updates = cls.get_or_insert('cms_updates', updates=dict()).updates
            if cid in cms_updates:   # cid modified has dt microseconds
                if cid_modified >= datetime.strptime(cms_updates[cid], '%Y-%m-%d %H:%M:%S'):
                    if (datetime.now() - timedelta(days=1)) > cid_modified:
                        del cms_updates[cid]
                        cls(id='cms_updates', updates=cms_updates).put_async()
                    return True
                return False         # reload the template
            return True                    
    

    有趣。但是每个环境(实例)都有自己的缓存。由于在SiteTemplates中检测到更新的实例会重置加载程序中的update标志(r.update=True),因此如何通知其他常驻实例发生了更新。是的,但是由于cache_size=0,所有实例都依赖字节码。有趣的是。但是每个环境(实例)都有自己的缓存。由于在SiteTemplates中检测到更新的实例会重置加载程序中的update标志(r.update=True),因此如何通知其他常驻实例发生了更新。是的,但由于cache_size=0,所有实例都依赖字节码。