Как получить доступ к моделям Django из запланированного сценария? - PullRequest
0 голосов
/ 20 октября 2019

TL; DR:

У меня есть приложение, в котором я хочу запускать процедуру каждый день в полночь (для этого я использую APScheduler). В середине этой процедуры предполагается получить доступ к данным нескольких моделей Django.

Логика:

Django работает> запустить apps.py> запустить scheduler.py> запустить рутину.py> получить доступ к models.py.

Исключения приведены в нижней части поста.

- Вот подробности:

Мой каталог такой:

myproject/
- manage.py

+ myproject/
-- settings.py
-- wsgi.py
-- ...

+ myapp/
-+ static/
-+ templates/
-- admin.py
-- apps.py
-- models.py
-- views.py
-- scheduler.py  #<<<<<<<<<<
-- routine.py    #<<<<<<<<<<
-- ...

myapp / models.py

class MyModel(models.Model):
    field1 = models.DateField(auto_now=True)
    field2 = models.DecimalField(max_digits=19, decimal_places=16)
    ...

myapp / apps.py

from django.apps import AppConfig
from .scheduler import ScheduledRoutine

class MyAppConfig(AppConfig):
    name = 'myapp'

    def ready(self):
        routine = ScheduledRoutine()
        routine.start()

myapp / scheduler.py

from .routine import MyRoutine
#from ..routine import MyRoutine   # See error nr3 <<<<<<<<<
from apscheduler.schedulers.background import BackgroundScheduler

class ScheduledRoutine(object):

    def start(self):
        self.scheduler = BackgroundScheduler()
        startdate = datetime.now() #For brevity assume datetime object
        self.scheduler.add_job(self.routine, 'interval', days=1, start_date=startdate)
        self.scheduler.start()

    def routine(self):
        data = MyRoutine()

myapp / рутинный.py

import os
os.environ["DJANGO_SETTINGS_MODULE"] = "myproject.settings"
import django
django.setup()

from .models import MyModel
#from myapp.models import MyModel  # See error nr3 <<<<<<<<<

class MyRoutine(object):
    def __init__(self, arg):
        self.arg = arg
        data = MyModel.objects.filter(reliable=True)
        self.do_something(data)

- Исключения и что не работает

Я уже пробовал несколько вещей, это те, которые япомните:

- Ошибка Nr1:

При текущем состоянии вещей (как показано выше) это ошибка:

Watching for file changes with StatReloader
Exception in thread django-main-thread:
Traceback (most recent call last):
  File "C:\Python\Python37\lib\threading.py", line 917, in _bootstrap_inner
    self.run()
  File "C:\Python\Python37\lib\threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
  File "C:\venv\lib\site-packages\django\utils\autoreload.py", line 54, in wrapper
    fn(*args, **kwargs)
  File "C:\venv\lib\site-packages\django\core\management\commands\runserver.py", line 109, in inner_run
    autoreload.raise_last_exception()
  File "C:\venv\lib\site-packages\django\utils\autoreload.py", line 77, in raise_last_exception
    raise _exception[1]
  File "C:\venv\lib\site-packages\django\core\management\__init__.py", line 337, in execute
    autoreload.check_errors(django.setup)()
  File "C:\venv\lib\site-packages\django\utils\autoreload.py", line 54, in wrapper
    fn(*args, **kwargs)
  File "C:\venv\lib\site-packages\django\__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "C:\venv\lib\site-packages\django\apps\registry.py", line 91, in populate
    app_config = AppConfig.create(entry)
  File "C:\venv\lib\site-packages\django\apps\config.py", line 90, in create
    module = import_module(entry)
  File "C:\Python\Python37\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "C:\venv\myproject\myapp\apps.py", line 2, in <module>
    from .scheduler import ScheduledRoutine
  File "C:\venv\myproject\myapp\scheduler.py", line 6, in <module>
    from .routine import MyRoutine
  File "C:\venv\myproject\myapp\routine.py", line 10, in <module>
    django.setup()
  File "C:\venv\lib\site-packages\django\__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "C:\venv\lib\site-packages\django\apps\registry.py", line 83, in populate
    raise RuntimeError("populate() isn't reentrant")
RuntimeError: populate() isn't reentrant

- Ошибка Nr2:

Поскольку routine.py находится внутри папки myapp/, и она пытается сослаться на myproject/settings.py Я попытался добавить . (также пробовал ..) к ссылкекак это:

os.environ["DJANGO_SETTINGS_MODULE"] = ".myproject.settings"

и это:

os.environ["DJANGO_SETTINGS_MODULE"] = "..myproject.settings"

Оба возвращают одинаковые исключения:

TypeError: the 'package' argument is required to perform a relative import for '.myproject.settings'

- Ошибка №3: ​​

Из-за той же проблемы, упомянутой выше (ссылка на settings.py, то есть myproject/settings.py), я попытался переместить routine.py вродительская папка, поэтому мне нужно было изменить импорт в routine.py и scheduler.py на их закомментированные версии . Это привело к этому исключению:

ValueError: attempted relative import beyond top-level package

- Ошибка Nr4:

Кроме того, запуск django со следующими комментариями (в рутине .py)

#os.environ["DJANGO_SETTINGS_MODULE"] = "myproject.settings"
#import django
#django.setup()

поднимает django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet. в значительной степени то, как все начиналось.

Редактировать: - Ошибка Nr5: Использование этого в рутинном.py вызывает ту же ошибку, что и Nr1.

from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_wsgi_application()

Мне кажется очевидным, что проблема в том, как я пытаюсь получить доступ к моделям в routine.py, а не в планировщике. Что еще я могу попробовать?

1 Ответ

1 голос
/ 22 октября 2019

Вы можете попробовать создать пользовательскую команду Django , чтобы вы могли создать команду типа python manage.py myroutine и использовать планировщик (например, cron) для ее запуска. Если вы сделаете это, можете избежать всего этого в своем коде:

os.environ["DJANGO_SETTINGS_MODULE"] = "myproject.settings"
import django
django.setup()

Я знаю, что это не совсем решение вашей проблемы, но это обходной путь.

...