いくつかのデータを含むファイルがあります – data.txt (適切なローカリゼーションで存在します)。アプリを起動する前にdjangoアプリがこのファイルを処理し、変更ごとに(再起動せずに)反応することを望みます。それを行う最良の方法は何ですか?
4 に答える
起動時に、 initで必要なことを行うミドルウェアを作成し、その後 init から django.core.exceptions.MiddlewareNotUsed を発生させることができるため、django はそれを要求処理に使用しません。ドキュメント
また、ミドルウェアinitは、最初のリクエスト時ではなく、起動時に呼び出されます。ファイルの変更に反応するには、https://github.com/gorakhargosh/watchdogを使用できます (使用例はここにあります)。したがって、ミドルウェアのどこかで開始することも、データベースの更新のみの場合は、スーパーバイザーなどを介して実行され、このファイルを監視してデータベースを更新する別のスクリプト (または django 管理コマンド) を作成することもできます。
しばらく前に、 Python モジュールを「ホットスワップ」するメカニズムを見つけようとしていました。それはまさにあなたが必要としているものではありませんが、私が提案した実装を使用して、構成ファイルの変更を監視し、それに応じて行動することができるかもしれません。
私が提案したコードは次のとおりです (NFS ファイル システムで作業しているため、inotify は使用しませんでした)。
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()
オプションは、ファイルシステムの変更を監視するpynotifyである可能性がありますが、Linux でのみ機能します。
それ以外の場合runserver
は、同じことを行うと思われるコマンドのコードを見てください (autoreload モジュールのコードはhere です)。
アプリを起動する前にコマンドを実行するには、設定モジュールにコードを記述できると思います。
おそらく、変更ごとにファイルを検索するオブジェクトを設定に入れることができます。...つまり:ファイルをロードし、変更された場合にこれをリロードするクラスを作成します
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