我的Django应用程序(主要基于REST框架)目前在管理页面上生成不能解析的URL.预期的结果是Django Admin的登录提示符提交表单,并将POST发送给/admin/login.Django作为表单提交URL传递的结果URL是/$default/admin/login,返回的是带有更钝的/$default/$default/admin/login/的404.

我假设我的Django配置或serverless.yml中存在某种配置错误.

按照下面的serverless.yml条,我正在使用API Gateway V2、通过WSGI的Django和Lambda函数.

service: api
app: api
org: myapp
frameworkVersion: '3'
provider:
  name: aws
  runtime: python3.8
functions:
  serve:
    handler: wsgi_handler.handler
    timeout: 20
    environment:
      DB_NAME: ${param:db_name}
      DB_PASSWORD: ${param:db_password}
      DB_USER: ${param:db_user}
      DB_PORT: ${param:db_port}
      DB_HOST: ${param:db_host}
    events:
      - httpApi: "*"
  migration:
    handler: migrate.handler
    timeout: 60
    environment: 
      DB_NAME: ${param:db_name}
      DB_PASSWORD: ${param:db_password}
      DB_USER: ${param:db_user}
      DB_PORT: ${param:db_port}
      DB_HOST: ${param:db_host}
custom:
  wsgi:
    app: myapp.wsgi.application
plugins:
  - serverless-python-requirements
  - serverless-wsgi

我的URL非常标准:

from django.contrib import admin
from django.urls import path, include

from rest_framework.schemas import get_schema_view

schema_view = get_schema_view(
    title="MyApp",
    description="MyApp Universal API",
    version="1.0.0",
)

urlpatterns = [
    path("admin/", admin.site.urls),
    path("user/", include("myapp.core.urls"), name="user"),
    path("openapi", schema_view, name="openapi-schema"),
]

我的配置更加标准:

import os
from pathlib import Path
from dotenv import load_dotenv

load_dotenv()

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


# 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 = "not for you :)"

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['*']

if 'CODESPACE_NAME' in os.environ:
    codespace_name = os.getenv("CODESPACE_NAME")
    codespace_domain = os.getenv("GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN")
    CSRF_TRUSTED_ORIGINS = [f'https://{codespace_name}-8000.{codespace_domain}']

ROOT_URLCONF = "myapp.urls"

# Application definition

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    'rest_framework',
    "myapp.core",
]

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

X_FRAME_OPTIONS = "ALLOW-FROM preview.app.github.dev"

ROOT_URLCONF = "myapp.urls"

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR / "myapp" / "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 = "myapp.wsgi.application"


STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

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

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DB_NAME', 'neondb'),
        'USER': os.environ.get('DB_USER', 'postgres'),
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': os.environ.get('DB_HOST', 'localhost'),
        'PORT': os.environ.get('DB_PORT', 5432),
    }
}


# 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",
    },
]


# 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/

STATICFILES_DIRS = [
    BASE_DIR / "myapp" / "static",
]

STATIC_URL = "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"

STATICFILES_STORAGE = 'storages.backends.s3boto3.S3StaticStorage'

AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = "myapp-django-static"

AUTH_USER_MODEL = 'core.User'

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticatedOrReadOnly',
    )
}

对于生成的错误消息:

enter image description here

任何帮助(或 idea )都将不胜感激!

我曾try 修改serverless.yml的路径 struct ,并一直在Django源代码中寻找任何提示,但都无济于事.当然,我只想让Django管理员工作.至于应用程序的其余部分,它运行得很好,因为API本身并不是自引用的.Django 只是没有返回正确的路径.

简而言之,Django 认为我所有的路由都有/$default/个前缀,但事实并非如此.我正在寻找一个解决方案来强制Django发送的路径为/,或者为我的无服务器配置寻找一个修复程序来缓解这个问题.

推荐答案

我设法用一个相当不错的Django设置选项解决了这个问题. https://docs.djangoproject.com/en/4.1/ref/settings/#force-script-name

虽然这不能解释为什么它要解决通向/$default/的路径,但它does缓解了这个问题.

如果您将其用于与我的用例不同的用例,并且您的路径位于子目录中(例如,与我的问题相反),那么您可以将您的路径添加到FORCE_SCRIPT_NAME.

有关更多信息,请参阅我提供的链接.

将以下内容添加到您的应用程序的settings.py或您用作DJANGO_SETTINGS_MODULE的任何文件中.

# Force Django to resolve the URL to the root of the site
# This is required for API Gateway <- WSGI -> Django path resolution to work properly.
FORCE_SCRIPT_NAME = ""

Django相关问答推荐

Django ORM Groupby

如何在Django模板中为无效词典查找打开异常?

如何在 Django 测试中发送带有图像字段查询参数的 POST 请求

如何在 Django REST Framework API 响应中使用多标签过滤器?

Django:获取每组最新的N条记录

防止 Django 从表单集中保存特定表单

AttributeError:模块rest_framework.serializers在 Swagger 中的 Django 中没有属性NullBooleanField

Django授权判断具有通配符模式的URL

"" 需要有字段 "id" 的值才能使用这种多对多关系

Django 模型命名约定

Django 模板中的 Handlebars.js

如何从 django 模板生成静态 html 文件?

Django ORM,按天分组

删除所有实例后,Django 模型实例主键不会重置为 1

在 Bootstrap 中使单击的选项卡处于活动状态

django npm 和 node 包架构

使用 scrapy 访问 Django 模型:定义 Django 元素的路径

如何在 Django 和 django-jsonfield 中将 JSONField 的默认值设置为空列表?

更改 Django ModelChoiceField 以显示用户的全名而不是用户名

使用 Django REST 框架从多个模型返回结果