【问题标题】:Processing some file before starting app and reacting for every change在启动应用程序之前处理一些文件并对每次更改做出反应
【发布时间】:2013-04-26 04:23:49
【问题描述】:

我有一个包含一些数据的文件 - data.txt(存在于适当的本地化中)。我希望 django 应用程序启动应用程序之前处理此文件并对每次更改做出反应(无需重新启动)。最好的方法是什么?

【问题讨论】:

  • 您希望应用程序如何反应,“处理”文件是什么意思?在启动应用程序之前处理 似乎没有多大意义。为什么不在视图函数的请求-响应周期中处理数据? (如果数据量大,可以使用一些异步任务队列来处理数据并在DB中反映进度,如果数据还没有准备好,则在视图函数的HTTP响应中返回适当的错误。)
  • 此文件用于存储有关应用程序的额外信息。数据不会很重,这个概念不是我的:)
  • “处理”是指数据库上的适度更新。 “反应”是指检测文件的变化和新的处理。

标签: python django


【解决方案1】:

对于启动,您可以在 init 中编写执行所需操作的中间件,然后从 init 中引发 django.core.exceptions.MiddlewareNotUsed,因此 django 不会使用它用于任何请求处理。 docs

中间件 init 将在启动时调用,而不是在第一次请求时调用。 至于对文件更改的反应,您可以使用https://github.com/gorakhargosh/watchdog(可以找到使用示例here)。 所以你也可以在中间件的某个地方启动它,或者如果它只有数据库更新,你可以创建一个单独的脚本(或 django 管理命令),它将通过主管或类似的东西运行,并将监视这个文件并更新数据库。

【讨论】:

    【解决方案2】:

    一个选项可以是pynotify,用于监视文件系统的更改,但它仅适用于 Linux。

    否则看runserver命令的代码似乎做同样的事情(自动重载模块的代码是here)。

    要在启动应用程序之前运行命令,我想您可以在设置模块中编写一些代码。

    【讨论】:

      【解决方案3】:

      也许您可以在设置中放置一个对象,该对象将在每次更改时查找文件。 ... IE : 创建一个类,该类将加载文件并在修改后重新加载该类

      class ExtraConfigWatcher(object):
          def __init__(self, file):
              self.file = file
              self.cached = dict()
              self.last_date_modified = None
      
          def update_config(self):
              """
              update the config by reloading the file
              """
              if has_been_modified(self.file, self.last_date_modified):
                  # regenerate the config with te file.
                  self.cached = get_dict_with_file(self.file)
                  self.last_date_modified = time.time()
          def __getitem__(self, *args, **kwargs):
              self.update_config()
              return self.cached.__getitem__(*args, **kwargs)
      
          def __setitem__(self, *args, **kwargs):
              raise NotImplemented("you can't set config into this")
      

      在settings.py中:初始化这个对象

      EXTRA_CONFIG = ExtraConfigWatcher("path/to/the/file.dat")
      

      在 myapps/views.py 中:导入设置并使用 EXTRA_CONFIG

      from django.conf import settings
      def dosomthing(request):
          if settings.EXTRA_CONFIG["the_data_from_the_file"] == "foo":
              # bouhh
      

      【讨论】:

        【解决方案4】:

        不久前,我试图找到"hot-swap" Python modules 的机制。虽然这并不完全是您所需要的,但也许您可以使用我提出的实现,并监视您的配置文件以进行修改并采取相应的行动。

        我提出的代码如下(我没有使用inotify,因为我在NFS文件系统中工作):

        import imp
        import time
        import hashlib
        import threading
        import logging
        
        logger = logging.getLogger("")
        
        class MonitorThread(threading.Thread):
            def __init__(self, engine, frequency=1):
                super(MonitorThread, self).__init__()
                self.engine = engine
                self.frequency = frequency
                # daemonize the thread so that it ends with the master program
                self.daemon = True 
        
            def run(self):
                while True:
                    with open(self.engine.source, "rb") as fp:
                        fingerprint = hashlib.sha1(fp.read()).hexdigest()
                    if not fingerprint == self.engine.fingerprint:
                        self.engine.notify(fingerprint)
                    time.sleep(self.frequency)
        
        class Engine(object):
            def __init__(self, source):
                # store the path to the engine source
                self.source = source        
                # load the module for the first time and create a fingerprint
                # for the file
                self.mod = imp.load_source("source", self.source)
                with open(self.source, "rb") as fp:
                    self.fingerprint = hashlib.sha1(fp.read()).hexdigest()
                # turn on monitoring thread
                monitor = MonitorThread(self)
                monitor.start()
        
            def notify(self, fingerprint):
                logger.info("received notification of fingerprint change ({0})".\
                                format(fingerprint))
                self.fingerprint = fingerprint
                self.mod = imp.load_source("source", self.source)
        
            def __getattr__(self, attr):
                return getattr(self.mod, attr)
        
        def main():
            logging.basicConfig(level=logging.INFO, 
                                filename="hotswap.log")
            engine = Engine("engine.py")
            # this silly loop is a sample of how the program can be running in
            # one thread and the monitoring is performed in another.
            while True:
                engine.f1()
                engine.f2()
                time.sleep(1)
        
        if __name__ == "__main__":
            main()
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-11-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-08-09
          • 2020-09-13
          • 2019-12-15
          相关资源
          最近更新 更多