You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行Django测试时遇AttributeError: 'NoneType'无rsplit属性错误求助

问题描述

在Windows 10的Docker环境中运行测试代码self.client.get("/")时,抛出AttributeError: 'NoneType' object has no attribute 'rsplit'错误。其他简单模型测试和应用本身运行正常,且该测试在另一个项目中可正常执行。

完整错误堆栈

Traceback (most recent call last):
  File "/usr/src/app/app/tests/test.py", line 5, in test_test
    resp = self.client.get("/")
           ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 836, in get
    response = super().get(path, data=data, secure=secure, **extra)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 424, in get
    return self.generic(
           ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 541, in generic
    return self.request(**r)
           ^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 805, in request
    response = self.handler(environ)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 140, in __call__
    self.load_middleware()
  File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 61, in load_middleware
    mw_instance = middleware(adapted_handler)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/whitenoise/middleware.py", line 105, in __init__
    self.add_files(self.static_root, prefix=self.static_prefix)
  File "/usr/local/lib/python3.11/site-packages/whitenoise/base.py", line 107, in add_files
    self.update_files_dictionary(root, prefix)
  File "/usr/local/lib/python3.11/site-packages/whitenoise/base.py", line 119, in update_files_dictionary
    self.add_file_to_dictionary(url, path, stat_cache=stat_cache)
  File "/usr/local/lib/python3.11/site-packages/whitenoise/base.py", line 130, in add_file_to_dictionary
    static_file = self.get_static_file(path, url, stat_cache=stat_cache)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/whitenoise/base.py", line 202, in get_static_file
    self.add_cache_headers(headers, path, url)
  File "/usr/local/lib/python3.11/site-packages/whitenoise/base.py", line 223, in add_cache_headers
    if self.immutable_file_test(path, url):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/whitenoise/middleware.py", line 177, in immutable_file_test
    static_url = self.get_static_url(name_without_hash)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/whitenoise/middleware.py", line 200, in get_static_url
    return staticfiles_storage.url(name)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/utils/functional.py", line 266, in inner
    self._setup()
  File "/usr/local/lib/python3.11/site-packages/django/contrib/staticfiles/storage.py", line 496, in _setup
    self._wrapped = get_storage_class(settings.STATICFILES_STORAGE)()
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/core/files/storage.py", line 419, in get_storage_class
    return import_string(import_path or settings.DEFAULT_FILE_STORAGE)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/utils/module_loading.py", line 25, in import_string
    module_path, class_name = dotted_path.rsplit(".", 1)
                              ^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'rsplit'

测试文件

from django.test import TestCase

class TestTest(TestCase):
    def test_test(self):
        resp = self.client.get("/")

docker-compose.yml(敏感数据仅用于本地开发)

version: "3.9"

services:
  web:
    build: .
    command: python /code/manage.py runserver 0.0.0.0:8080
    volumes:
      - .:/code
    ports:
      - 8080:8080
      - 9999:9999
    depends_on:
      - db
  db:
    image: postgres:14
    environment:
      POSTGRES_USER: postgres
      POSTGRES_DB: blog
      POSTGRES_PASSWORD: 7895
    ports:
      - 5432:5432
    volumes:
      - postgres_data:/var/lib/postgresql/data/

volumes:
  postgres_data:

settings.py

"""
Django settings for blogapp project.

Generated by 'django-admin startproject' using Django 4.1.3.

For more information on this file, see
https://docs.djangoproject.com/en/4.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.1/ref/settings/
"""


from pathlib import Path
import os

from dotenv import find_dotenv, load_dotenv
import dj_database_url

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

load_dotenv(find_dotenv())

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv("SECRET_KEY")

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv("DEBUG", "0").lower() in ["true", "t", "1"]

ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS").split(" ")
CSRF_TRUSTED_ORIGINS = os.getenv("CSRF_TRUSTED_ORIGINS").split(" ")


# Application definition

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "whitenoise.runserver_nostatic",
    "django.contrib.staticfiles",
    "app.apps.AppConfig",
    "tinymce",
    "storages",
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "whitenoise.middleware.WhiteNoiseMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]


ROOT_URLCONF = "blogapp.urls"

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR.joinpath("templates")],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

WSGI_APPLICATION = "blogapp.wsgi.application"


# Database
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases

DATABASES = {"default": dj_database_url.config()}

# Password validation
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
    },
]


TINYMCE_JS_URL = "https://cdn.tiny.cloud/1/jys86spz5w4zp7jbfbr16eorvcw4sx1j2yg6q26namjws4do/tinymce/5/tinymce.min.js"
TINYMCE_COMPRESSOR = True


# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/

LANGUAGE_CODE = "en-us"

TIME_ZONE = "UTC"

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/

STATIC_URL = "static/"
MEDIA_URL = "/media/"
MEDIA_ROOT = Path(BASE_DIR).joinpath("upload")
STATIC_ROOT = BASE_DIR / "static/"

# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

# S3 Bucket
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
AWS_STORAGE_BUCKET_NAME = os.getenv("AWS_STORAGE_BUCKET_NAME")
DEFAULT_FILE_STORAGE = os.getenv("DEFAULT_FILE_STORAGE")
AWS_S3_FILE_OVERWRITE = os.getenv("AWS_S3_FILE_OVERWRITE", "0").lower() in ["true", "t", "1"]
AWS_DEFAULT_ACL = os.getenv("AWS_DEFAULT_ACL")
STATICFILES_STORAGE = os.getenv("STATICFILES_STORAGE")
AWS_S3_REGION_NAME = os.getenv("AWS_S3_REGION_NAME")

解决方案

错误根源是settings.py中STATICFILES_STORAGE和DEFAULT_FILE_STORAGE通过os.getenv()获取值,但本地开发环境的.env文件中未配置这两个变量,导致它们的值为None。Django尝试导入None作为存储类路径时,调用rsplit()方法就会抛出错误。

解决步骤:

  • 方法一:在本地.env文件中添加默认值(使用Django内置存储类):
DEFAULT_FILE_STORAGE = django.core.files.storage.FileSystemStorage
STATICFILES_STORAGE = django.contrib.staticfiles.storage.StaticFilesStorage
  • 方法二:直接在settings.py中给变量设置默认值,避免获取不到环境变量时为None:
DEFAULT_FILE_STORAGE = os.getenv("DEFAULT_FILE_STORAGE", "django.core.files.storage.FileSystemStorage")
STATICFILES_STORAGE = os.getenv("STATICFILES_STORAGE", "django.contrib.staticfiles.storage.StaticFilesStorage")

生产环境需要用S3存储时,再单独配置对应存储类(比如storages.backends.s3boto3.S3Boto3Storage)即可。

内容的提问来源于stack exchange,提问作者gook

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 20:47:39