在启动app之前处理一些文件并对每个更改做出反应

时间:2013-04-20 16:10:01

标签: python django

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

4 个答案:

答案 0 :(得分:3)

对于启动,您可以编写在 init 中执行所需操作的中间件,然后从 init 中提升django.core.exceptions.MiddlewareNotUsed,这样django就不会使用了它适用于任何请求处理。 docs

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

答案 1 :(得分:1)

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

否则请查看似乎执行相同操作的runserver命令代码(自动重载模块的代码为here)。

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

前段时间我试图找到"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()