【问题标题】:Django in subdirectory - admin site is not working子目录中的 Django - 管理站点不工作
【发布时间】:2017-12-12 17:11:09
【问题描述】:

我已将我的 Django 项目部署在服务器 (dns_name_of_my_page/notes) 的子目录中。我在这个项目中的应用程序可以通过 dns_name_of_my_page/notes/app/ 访问。不幸的是,如果整个 Django 项目位于托管服务器上 public_html 的子目录“notes”中,则管理站点无法正常工作。当我进入管理站点 (dns_name_of_my_page/notes/admin/) 时,重定向到没有子目录名称的 URL (dns_name_of_my_page/adminlogin/?next=//admin/),这是不可接受的。应该是 dns_name_of_my_page/notes/adminlogin/?next=/notes/admin/

这是我在项目中的 URL 配置:

urlpatterns = [
    url(r'^/?app/?', include('app.urls')),
    url(r'^/?$', views.index, name='index'),
    url(r'^/?admin/?', admin.site.urls),
]

这是我在应用中的 URL 配置:

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^(?P<num>[0-9]+)/?', views.num, name='num'),
]

我试过设置

FORCE_SCRIPT_NAME = '/notes/'

SUB_SITE = "/notes/"

在 settings.py 中,但对我没有帮助。

你有没有在子目录中运行 Django 应用时遇到过这种问题?

【问题讨论】:

  • 您为项目初始化了日志记录?当您想访问管理页面时遇到什么错误?静态文件有效吗?
  • 我认为你的url(r'^/?admin/?', admin.site.urls), 应该是url(r'^admin/', admin.site.urls), 没有?...
  • 同意。 Django 可以为你处理斜杠。 docs.djangoproject.com/en/1.10/ref/settings/#append-slash
  • 路由adminlogin在哪里定义?您确定 next 值没有硬编码在某些视图代码中吗?
  • 当你使用FORCE_SCRIPT_NAME时发生了什么?这就是你应该如何完成这项工作。您是否在当前设置中使用它?

标签: python django


【解决方案1】:

我今天被这个问题发现了,虽然有许多类似的问题 [1],但从我解决这个问题的经验来看,答案在某种程度上是一种混合体。

您的问题中缺少的一个细节是您正在使用的服务器设置。为了解释我的解决方案,它有助于理解它是如何与 Django 方面结合使用的。

我一直在解决的问题包括访问 Django 管理员(以及大多数其他应用程序,例如 Auth)的问题是让服务器充当多个独立 django 项目的主机。目的是让 URI 以 http://my.server.com/project_name/foo/bar/ [2] 开头。就每个项目而言,它在 my.server.com 上运行,并且只处理 /foo/bar(在大多数生产/单应用程序系统中就是这种情况,以及使用 manage.py runserver 进行本地开发)

我使用 NGinx 作为反向代理,在我的域的端口 80 和 443 上进行侦听。在该服务器中,我有一个 location 设置来代理每个子项目的 Nginx 服务 + Gunicorn。

nginx默认位置配置如下:

location /project_name {
    proxy_set_header X-Forwarded-Protocol $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $http_host;
    proxy_set_header X-Scheme $scheme;
    proxy_set_header X-Forwarded-For $remote_addr;

    proxy_pass http://localhost:7001/;
}

每个项目自己的 nginx+gunicorn 服务的设置与本主题并不特别相关,但您可以看到它呈现在自己的本地服务端口上。

此配置将为http://my.server.com/foo/bar/ 提供有效请求。这让我们现在可以说服 Django 为它在输出中生成的所有 URL 添加 /project_name/ 前缀。

为此,您需要了解一些关键设置,它们是:

USE_X_FORWARDED_HOST = True
FORCE_SCRIPT_NAME = '/project_name/'

这会导致 Django 尊重 nginx 传递的标头更改,并触发它自己的进程来重写模板中 {% url name %} 标记的输出。

SESSION_COOKIE_PATH = '/project_name/'

这应该有助于区分该域上的多个登录,并且意味着您可以登录一个项目,但不能登录另一个项目(或混淆它)。

STATIC_FILES_ROOT='\path\on\disk\as\in\your\nginx\config\for\static\'
STATIC_FILES_URL='/project_name/static/'
MEDIA_FILES_ROOT='\path\on\disk\as\in\your\nginx\config\for\media\'
MEDIA_FILES_URL='/project_name/media/'

这些处理 `{% static blah %} 类型的模板标签和文件服务。

LOGIN_REDIRECT_URL='/project_name/'
LOGOUT_REDIRECT_URL='/project_name/'

这些处理使用 Auth 模块登录/退出服务的结果,并确保它在登录或注销时将用户发送回项目站点的根目录。您可以轻松地根据自己的需要定制这些内容,包括使用 url-conf 样式的正则表达式字符串,例如我们将在下面为管理页面执行的操作

ADMIN_URL=r'^admin/'

此设置与您网站 urls.py 中的这一行配对:

url(settings.ADMIN_URL, include(admin.site.urls)),   # default=r'^admin/'

这里的一个关键细节是,正则表达式前面没有 /,否则会尝试将其强制返回主机名,因此 FORCE_SCRIPT_NAME 指定的更改将起作用。

另外,请注意不要在模板中包含任何以 / 开头的硬编码 url(相对或其他),因为 Django 模板输出更改不会捕获这些。

按照这种方法,我已经能够在三个不同的系统中部署这些项目中的每一个,其中两个涉及它们作为该域或服务端口上唯一的 django 应用程序运行,剩下的一个是这个共享域设置,除了更改每个位置的设置值之外,不需要任何其他操作。


在您自己的代码示例中采用这种方法,我建议您正在寻找对以下方面的更改:

urlpatterns = [
    url(r'^admin/?', admin.site.urls),
    url(r'^app/?', include('app.urls')),
    url(r'^$', views.index, name='index'),
]

为了帮助搜索和匹配顺序,我重新安排了 admin 排在第一位,而 empty/home/root 匹配模板排在最后。否则你的 FORCE_SCRIPT_NAME 设置是正确的。


[1] 例如multiple instances of django on a single domain ; Is it possible to host multiple django projects under the same domain? ; how to deploy django under a suburl behind nginx

[2] 默认服务器实际上也在处理 SSL 转换,因为服务在 https 上提供,但在内部,localhost 端口(隐藏在机器防火墙后面)只处理 http。

【讨论】:

    猜你喜欢
    • 2012-06-09
    • 2023-01-30
    • 1970-01-01
    • 1970-01-01
    • 2017-12-26
    • 1970-01-01
    • 2016-11-05
    • 2017-02-10
    • 1970-01-01
    相关资源
    最近更新 更多