【Django】如何在测试时不使用manage.py,直接运行独立的Python脚本的方法

综述

当您使用Django框架来实现Python程序时,是否有时候想要运行一个单独的脚本文件进行测试?

通常情况下,Django应用程序是通过manage.py脚本来执行的,但有时候我们希望在与项目结构独立的情况下执行脚本。

当我想查看Django的ORM输出结果与数据库交互时,或者想要确认与项目和应用程序目录无关的情况下会出现什么行为时,我会想使用它。
在本文中,我将介绍如何执行独立脚本。

代码的基础是从 Django 教程中的 polls 应用程序中引用的,但与此并没有太大关系。
Django 应用程序的第一个创建,第 1 章。

The given sentence “前提” can be paraphrased in Chinese as:

– 先决条件 jué

目录结构如下。

.
├── mysite
│   ├── mysite
│   │   ├── (略)
│   ├── polls
│   │   ├── (略)
│   ├── manage.py
│   └── sample.py  <- このスクリプトを実行させる

我正在使用 Python 的版本是 3.8.16 和 Django 的版本是 4.1。

示例代码

以下是示例代码。

import os
import django

# Djangoの設定を読み込む
os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'mysite.settings')

# Djangoアプリケーションの初期化
django.setup()

# (モデルにアクセスするコードが必要であればこれより下に書く)
from sample.models import Sample

# 以下に実行したいコードを書く

使用上述的方法,您可以导入模型并与数据库表进行协同。
例如,您可以添加代码来执行数据库查询,操作模型以获取或修改数据。

可以执行独立的脚本,测试所需功能,进行与数据库的交互,与Django项目的结构无关。

代码解释

逐一解释每个人在做什么。

首先,我们将需要的模块导入后,
使用os.environ.setdefault()将Django的配置加载到当前脚本中。

调用`django.setup()`会初始化Django应用程序。这将设置Django环境,并使得与模型和数据库的交互成为可能。

只有这么多,但由于遇到了各种错误,我将介绍上述代码的详细信息。

介绍3种错误

由于导入语句的顺序错误而导致的错误

首先,以下是错误信息。

    raise AppRegistryNotReady("Apps aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

由于无法正确初始化Django应用程序而导致错误。

有必要推迟访问模块。例如,在上述示例中,如果在初始化代码之前写入“from sample.models import Sample”,将会导致错误。

②由于os.environ.setdefault未进行设定,导致错误。

接下来是以下的错误。

    raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: Requested setting LOGGING_CONFIG, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

如果Django的配置不正确,就会发生这种情况,正如它所说的“settings are not configured”,表明设置没有正确配置。

当没有写上”os.environ.setdefault(“DJANGO_SETTINGS_MODULE”, ‘mysite.settings’)”时,会出现上述情况。

“DJANGO_SETTINGS_MODULE”在错误消息中是指定Django在运行时使用哪个配置文件的环境变量。Django发现无法找到该配置文件或者未正确配置settings,因此会报错。

DJANGO_SETTINGS_MODULE环境变量是使用Python的os.environ设置的,它告诉正在运行的Django应用程序Django配置文件的位置。通常情况下,这个环境变量是在manage.py脚本中使用的,所以平时不需要担心它,但是如果要单独运行Django应用程序,就需要确保它能够正确加载配置。

的确,manage.py中有以下的描述,可以看出它正在加载settings.py文件。

#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()

顺便提一下,

export DJANGO_SETTINGS_MODULE=mysite.settings

通过执行这个命令,在shell环境中设置DJANGO_SETTINGS_MODULE环境变量为”mysite.settings”作为配置文件也是可行的。但是这只在当前的shell会话中有效,如果关闭了shell或者使用了docker,每次都需要重新设置,所以基本上我认为最好还是将其写在代码中,就像上面所述。

由于未配置django.setup()而导致的错误。

以下是第三个错误。

    raise AppRegistryNotReady("Apps aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

如果没有包含django.setup(),就会发生上述错误。
错误信息和①相同。
通过调用django.setup()可以成功设置Django并解决错误。

首先,关于`django.setup()`是什么的问题,它是一个函数,用于在使用Django应用程序之前设置必要的环境。具体来说,它包括从settings.py中加载设置、应用程序的初始化(如URL路由、模型准备、模板引擎设置等)以及准备数据库等等。

我想您通常不会看到这一句,但通常都是通过manage.py来内部执行django.setup(),所以不需要担心。如果不使用manage.py,可以明确指示,这样Django应用程序就可以从命令行或脚本中独立执行。

其他

最初我是这样实施的。

import os
from django.conf import settings

# Djangoの設定を読み込む
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
settings.configure()

import django

# Djangoアプリケーションの初期化
django.setup()

# 以下に実行したいコードを書く

然而,当尝试手动进行Django设置并使用settings.configure()时,出现了以下错误。这是由于Django无法确定模型属于哪个应用程序而引起的。

RuntimeError: Model class sample.models.Sample doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.

这个问题的解决方法如下所述。

【Django】关于”没有声明明确的app_label,并且在INSTALLED_APPS中也不在任何应用程序中”的错误。

看起来使用settings.configure()可以让Django自动加载配置,但还需要手动添加必要的配置元素。虽然可以通过以上方法解决问题,但是我觉得在INSTALLED_APPS和模型定义中逐个设置太麻烦了,所以我没有选择这个方法。上述的示例代码更加简洁清晰易懂。

bannerAds