【问题标题】:Call function right after starting django developement server. (Django/Python)启动 django 开发服务器后立即调用函数。 (Django/Python)
【发布时间】:2019-05-29 03:36:15
【问题描述】:

我试图在命令python manage.py runserver 之后立即调用函数,它可以是简单的打印。我读了一些东西,发现关于def ready(self) 的话题很有趣,比如这个 Overriding AppConfig.ready()Execute code when Django starts ONCE only? 我按照说明进行操作,但对于 django 2.1.3 版本它不起作用。当我收到一堆AppRegistryNotReady exceptions 时,不会调用一次就绪函数。我认为服务器启动后的调用函数是很常见的事情。它不应该带来这么多麻烦,但我仍然没有找到合适的解决方案

更新

我尝试了另一种解决方案

我创建这样的中间件类:

import time


class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        while True:
            print("true")
            time.sleep(5)

    def __call__(self, request):

        response = self.get_response(request)

        return response

现在我得到了正确的输出,例如:

Performing system checks...

System check identified no issues (0 silenced).
January 03, 2019 - 14:10:55
Django version 2.1.3, using settings 'CMS.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
true
true
true
true
true
true
true
.
.
.

但没有连接

【问题讨论】:

  • 您说的很清楚,但我只是要确保:您希望在服务器准备好获取请求时调用函数,而不是在它自己调用启动之后?跨度>
  • @CharlesLandau 是的,当服务器准备好时我想调用函数
  • 您必须了解“服务器启动后”是一个相当模糊的定义。如果您使用多处理设置(这是生产中最常见的情况),则每个进程将有一个“服务器启动”。如果进程由前端服务器管理(这也是最常见的情况),那么前端可能随时启动新的 django 进程。让我们不要谈论在负载平衡器后面有两个或更多前端服务器 - 这里“服务器启动”的定义是什么?
  • @CharlesLandau 我更新了问题
  • @brunodesthuilliers 我更新了问题

标签: python django function startup django-2.1


【解决方案1】:

我的解决方案有点不同,我愿意接受所有人的建议。 灵感来自@alfandango's answer to use wsgi.py to run the custom code one time and some other references类似于当前问题,指出将代码放在urls.py中将执行一次代码,但仅在第一次命中任何网址出现。 请注意,该解决方案仅在以下情况下有用/建议:

  1. 您想在系统首次运行时运行数据库命令/访问数据库
  2. 您只有一名工人。该代码还将为多个工作人员运行,但每个工作人员都会调用一次
  3. 如您所见,您可以将代码的执行延迟 1 秒(或更短)。

解决方案: STEP1:将以下代码添加到根 urls.py :

#normal URL.py invocation
urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^somepaths/', include((some_url, 'some_url'), namespace="some_urls")),
]

#define or import your function
def run_after_system_start():
    pass

#now run the functions
run_after_system_start()

STEP2:在 wsgi.py 中运行 wget 来调用 url.py #wsgi.py 的常规代码 导入操作系统

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'applications.settings')

import os
application = get_wsgi_application()


#below code hits itself(http://0.0.0.0) at some url to just invoke url.py and run the code once. The option for Wget are to enable no output or error is printed. It retries only once with a timeout of 1 second. Also the HIT type is of HTTP POST

try:
    os.system('wget -T 1 -q -o /dev/null -O "/dev/null" --tries=1 --post-data "" http://0.0.0.0/someurl')
except Exception as e:
    pass

其他参考资料:

  1. Wget No error message/output

【讨论】:

    【解决方案2】:

    编辑:

    我仍然不确定您要达到什么目标,并且评论者已经强调了一些重要的问题。首先,AppRegistryNotReady: Apps aren't loaded yet 错误真的令人沮丧,我很感激。我不确定您是如何组织项目的,因此无法提供确切的解决方案。这可能是您组织文件的方式以及您从哪里导入应用程序的 AppConfig 类。您是否将它或任何自定义函数或类放在您的应用程序包级别__init__.py 中,以便从那里导入?如果是这样,这似乎让 Django 感到困惑,请参阅 https://stackoverflow.com/a/34136825/2275482

    其次:

    我正在尝试在命令 python manage.py runserver 之后立即调用函数

    我认为我们正在努力理解您想要实现的目标,以及您是否将 Django 应用程序启动时间与服务器启动时间混为一谈。正如评论者所指出的,Web 服务器完全独立于 Django;这是一个单独的过程。

    即使是与 Django 捆绑的测试服务器也独立于您的 Django 应用程序。它只是为了方便而放置在那里的一个简单的开发服务器,但它不是必需的,也不应该在生产中使用。 Django 是按照PEP 333 构建的。 AFAIK,它适用于任何符合 PEP 333 的 WSGI Web 服务器,无论是 Apache 和 mod_wsgi、gunicorn 还是 uWSGI 等。如果您希望代码与您正在使用的服务器相关,您需要查看服务器文档。

    manage.py like django-admin 只是一个帮助开发的实用程序,请参阅https://docs.djangoproject.com/en/2.1/ref/django-admin/。当您调用manage.py runserver 时,您正在调用一个实用程序来加载您的应用程序并设置一个测试服务器。您可以在文件本身中看到执行流程、正在导入的实用程序等。此执行流程与使用生产服务器时发生的情况不同。

    据我所知,生产服务器会从根 wsgi.py 文件加载您的 django 应用程序。它甚至不会看manage.py

    所以这可以追溯到您是否尝试在服务器启动后发布消息,在这种情况下,这与 Django 无关,或者当您的 Django 应用程序启动时?

    如果您在 django 应用程序启动、启动并加载到服务器后尝试打印内容,那么您有很多选择。如果你真的想要,你可以编辑并添加到manage.py,但除此之外我不会篡改 Django 的核心。当使用不同的生产服务器时,这将被完全忽略。

    如果您想编辑无论正在使用的服务器如何都将加载的入口点,那么您可以编辑项目的wsgi.py 模块或单个应用程序AppConfig ready() 方法。

    如果您想构建独立于 Django 并在后台持续运行的东西,那么正如@bruno-desthuilliers 指出的那样,您需要构建一个单独的进程作为 cron 作业或使用 celery 甚至 django-carrot 如果您想要,虽然后者仍然链接到应用程序启动但可以作为一个单独的工作人员(我认为)。 django-carrot 只有非常简单的小任务功能..

    如果这没有任何帮助,我很抱歉,我可以尽我所能提供的信息。


    当我想在我的应用 AppConfig 的 ready() 方法中运行某些东西时,我遇到了类似的问题。对我来说,这是我的应用程序安装在我的 INSTALLED_APPS 设置变量中的方式。

    通常你会像这样注册你的应用程序:

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'my_app',
    ]
    

    但是,这将加载用于注册您的应用的基本 AppConfig 类。如果你自定义并覆盖了应用的AppConfig,这样你就可以声明自己的ready()方法,一旦应用实例化就会执行,你需要直接在INSTALLED_APPS中引用覆盖的AppConfig

    所以

    INSTALLED_APPS = [
            'django.contrib.admin',
            'django.contrib.auth',
            'django.contrib.contenttypes',
            'django.contrib.sessions',
            'django.contrib.messages',
            'django.contrib.staticfiles',
            'my_app.apps.MyAPPConfig', # MyAppConfig is the config class that inherits from AppConfig
        ]
    

    或者,如果您不希望在通过其 AppConfig 加载特定应用程序时执行此操作,因此不要通过 ready() 方法,而是当项目加载到服务器时,您可以在项目中放置一个 @ 987654342@应用加载后的模块

    application = get_wsgi_application()
    print('Hello World')
    

    希望有帮助

    【讨论】:

    • cf 我对这个问题的评论 - 如果您正在运行多进程服务器怎么办?
    • 问题是在manage.py runserver 完成加载时运行一个函数,这是一个测试服务器,而不是用于生产。 OP 没有明确说明此功能是仅用于测试还是用于生产。我将其解释为应用程序启动后,正如您所说的 server start 有点模棱两可。
    • 首先,您的答案与我给出的主题中的答案相同。当我在ready()内尝试使用简单打印的解决方案时,我得到输出2x打印,然后“执行系统检查......”首先这应该是相反的方式,首先“正在执行系统检查......”然后打印。无论如何,当我使用我的最终功能时,我会一直运行我得到AppRegistryNotReady: Apps aren't loaded yet
    • @KyluAce 我已经更新了我的答案,但很抱歉我不完全理解你想要做什么。这是我能给出的最佳答案,如果帮不上忙,请见谅。
    【解决方案3】:

    您可以在manage.py 的末尾添加函数调用,在您的支持文件之一中,如routes.py,等等。但!您表示希望在服务器准备好接收请求时调用该函数。

    覆盖AppConfig.ready() 用于将AppConfig 子类化并将其添加到应用注册表时。从您的问题中不清楚您是否遵循了该部分。您可以仔细检查您是否遵循here 的说明,以确保您已正确完成。

    【讨论】:

    • 现在我很确定我不能将AppConfig.ready() 与我的函数一起使用,所以我尝试在manage.py 末尾调用函数(我没有 routes.py 文件在我的项目中)但我得到AppRegistryNotReady: Apps aren't loaded yet.
    • 你不能使用 AppConfig.ready(),你应该尝试使用 SubclassOfAppConfig.ready()
    猜你喜欢
    • 1970-01-01
    • 2012-05-10
    • 1970-01-01
    • 1970-01-01
    • 2013-12-16
    • 2016-05-16
    • 2020-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多