【问题标题】:Perform model operations (only once) at server init在服务器初始化时执行模型操作(仅一次)
【发布时间】:2023-03-16 05:34:01
【问题描述】:

我有一个相当特殊的要求:应用程序应该能够将自己的正常运行时间显示为总小时数。这意味着我需要摆脱请求-响应周期并更新相关模型中的当前时间戳。

考虑到这一点,我按照here 给出的说明,将代码放入我应用程序的ready() 方法apps.py 中。当然,问题是我遇到了Apps aren't loaded yet 错误。我该如何解决这个问题?

想到的另一种方法是取消模型并将时间戳写入文件,但这是一种无法扩展的脆弱方法。如果我想在启动时存储大量的关系信息怎么办?

有人可以推荐吗?

======= 更新 =========

我使用的代码如下(我的项目叫jremind,我的应用叫remind)。

这是我的模型实例:

class Monitor(models.Model):
    # save automatically when object is saved()
    app_init_timestamp = models.DateTimeField(null=False, auto_now=True)

应用程序的__init__ 文件:

default_app_config = 'remind.apps.RemindConfig'

应用程序的apps.py 文件:

from django.apps import AppConfig
from remind.models import Monitor

class RemindConfig(AppConfig):
    name = 'remind'

    def ready(self):
        # There's only one instance
        monitor = Monitor.objects.get()[0]
        #Auto-update timestamp
        monitor.save()

这是我运行 ./manage.py runserver 时的完整堆栈跟踪:

(env) jremind$ ./manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
July 13, 2016 - 15:12:08
Django version 1.9, using settings 'jremind.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
^C(env) jremind$ ./manage.py runserver
Traceback (most recent call last):
  File "./manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/media/common/code/python/projects/jremind/env/lib/python3.4/site-packages/django/core/management/__init__.py", line 350, in execute_from_command_line
    utility.execute()
  File "/media/common/code/python/projects/jremind/env/lib/python3.4/site-packages/django/core/management/__init__.py", line 342, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/media/common/code/python/projects/jremind/env/lib/python3.4/site-packages/django/core/management/__init__.py", line 176, in fetch_command
    commands = get_commands()
  File "/media/common/code/python/projects/jremind/env/lib/python3.4/functools.py", line 448, in wrapper
    result = user_function(*args, **kwds)
  File "/media/common/code/python/projects/jremind/env/lib/python3.4/site-packages/django/core/management/__init__.py", line 71, in get_commands
    for app_config in reversed(list(apps.get_app_configs())):
  File "/media/common/code/python/projects/jremind/env/lib/python3.4/site-packages/django/apps/registry.py", line 137, in get_app_configs
    self.check_apps_ready()
  File "/media/common/code/python/projects/jremind/env/lib/python3.4/site-packages/django/apps/registry.py", line 124, in check_apps_ready
    raise AppRegistryNotReady("Apps aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

【问题讨论】:

  • ready() 方法在 应用程序准备就绪后调用。如果您仍然收到“应用程序尚未加载”消息,那么您做错了,在 ready() 方法之外。发布代码和相关的堆栈跟踪。
  • @solarissmoke 在问题中添加。请帮忙!

标签: django django-1.9


【解决方案1】:

您需要从方法内部导入模型:

def ready(self):
    from remind.models import Monitor

但是,您还应该注意warning in the documentation

尽管您可以如上所述访问模型类,但请避免在您的 ready() 实现中与数据库交互。这包括执行查询的模型方法(save()delete()、管理器方法等)...您的ready() 方法将在每个管理命令的启动期间运行。例如,即使测试数据库配置与生产设置分开,manage.py test 仍会针对您的生产数据库执行一些查询!

还有:

在通常的初始化过程中,ready方法只被Django调用一次。但在某些极端情况下,特别是在摆弄已安装应用程序的测试中,可能会多次调用 ready。在这种情况下,要么编写幂等方法,要么在 AppConfig 类上放置一个标志,以防止重新运行应该只执行一次的代码。

这样设置标志:

class RemindConfig(AppConfig):
    name = 'remind'
    ready_has_run = False

    def ready(self):
        if self.ready_has_run:
            return

        # Do your stuff here, and then set the flag
        self.ready_has_run = True

【讨论】:

  • 谢谢!做到了。但是考虑到有关测试的警告以及所有问题,我的问题有什么更好的解决方案?
  • @dotslash 我已经用一种方法(在文档中建议)编辑了答案,以防止代码再次运行,这应该可以处理大多数情况。也就是说,您可能需要在特定设置中试用并确保其正常工作。除了现阶段不尝试使用数据库之外,我真的不知道还有什么其他选择。
猜你喜欢
  • 1970-01-01
  • 2022-07-17
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 2015-05-06
  • 2021-12-02
  • 1970-01-01
相关资源
最近更新 更多