我正在使用Django backend和Vuejs frontend建立网站。在开发中,我分别使用python manage.py runserver
和yarn serve
分别启动了后端和前端。效果很好,我现在想部署该网站。为此,我运行了yarn build
,它在我的前端文件夹中创建了一个dist/
文件夹。所以我的结构是这样的:
cockpit
├── backend/
│ ├── cockpit/
│ │ ├── views.py
│ │ ├── css/
│ │ └── etc..
│ ├── settings/
│ │ └── settings.py
│ └── manage.py
└── frontend/
└── dist/
├── index.html
├── css/
└── js/
我现在想从我的django项目中提供frontend/dist/
中的源代码,以便可以使用uwsgi运行所有内容。为此,我尝试遵循this description。我有以下settings/urls.py
from django.contrib import admin
from django.urls import include, path, re_path
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path('cockpit/', include("cockpit.urls")),
re_path('', TemplateView.as_view(template_name='index.html')),
]
,然后在我的settings.py中设置以下设置:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['static'], # <== ADDED THIS
'APP_DIRS': True,
'OPTIONS': {
# removed to keep this example small
},
},
]
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, '../frontend/dist'),
]
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
print("BASE_DIR:", BASE_DIR)
print("STATIC_ROOT:", STATIC_ROOT)
print("STATICFILES_DIRS:", STATICFILES_DIRS)
印刷品向我展示了这一点:
BASE_DIR: /home/kramer65/repos/cockpit/backend
STATIC_ROOT: /home/kramer65/repos/cockpit/backend/static/
STATICFILES_DIRS: ['/home/kramer65/repos/cockpit/backend/../frontend/dist']
然后我运行`python manage.py collectstatic:
$ python manage.py collectstatic
150 static files copied to '/home/kramer65/repos/cockpit/backend/static'.
所以现在看起来像这样:
cockpit
├── backend/
│ ├── cockpit/
│ │ ├── views.py
│ │ ├── css/
│ │ └── etc..
│ ├── settings/
│ │ └── settings.py
│ └── manage.py
│ └── static/
│ ├── index.html
│ ├── css/
│ └── js/
└── frontend/
└── dist/
├── index.html
├── css/
└── js/
我通过运行http-server
文件夹中的(节点)backend/static/
进行了测试。在浏览器中,网站可以完美运行。下面是命令行的输出:
$ http-server
Starting up http-server, serving ./
Available on:
http://127.0.0.1:8080
http://192.168.0.104:8080
Hit CTRL-C to stop the server
[2020-05-18T13:50:58.487Z] "GET /" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0"
(node:5928) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated
[2020-05-18T13:50:58.671Z] "GET /css/chunk-vendors.2c7f3eba.css" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0"
[2020-05-18T13:50:58.679Z] "GET /css/app.e15f06d0.css" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0"
[2020-05-18T13:50:58.681Z] "GET /js/chunk-vendors.9c409057.js" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0"
[2020-05-18T13:50:58.687Z] "GET /js/app.c930fce5.js" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0"
我停止了此http-server
,启动了Django dev服务器并打开了浏览器。终端向我显示了这一点:
$ python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
May 18, 2020 - 17:57:00
Django version 3.0.6, using settings 'settings.settings'
Starting ASGI/Channels version 2.4.0 development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
HTTP GET / 200 [0.22, 127.0.0.1:33224]
HTTP GET /static/debug_toolbar/css/print.css 200 [0.04, 127.0.0.1:33232]
HTTP GET /static/debug_toolbar/css/toolbar.css 200 [0.05, 127.0.0.1:33234]
HTTP GET /static/debug_toolbar/js/toolbar.js 200 [0.02, 127.0.0.1:33232]
HTTP GET /static/debug_toolbar/js/toolbar.timer.js 200 [0.04, 127.0.0.1:33234]
HTTP GET /js/chunk-vendors.9c409057.js 200 [0.80, 127.0.0.1:33228]
HTTP GET /css/chunk-vendors.2c7f3eba.css 200 [0.94, 127.0.0.1:33224]
HTTP GET /js/app.c930fce5.js 200 [0.98, 127.0.0.1:33230]
HTTP GET /css/app.e15f06d0.css 200 [0.99, 127.0.0.1:33226]
HTTP GET /favicon.ico 200 [0.09, 127.0.0.1:33226]
在浏览器控制台中,我看到源似乎已加载,但是某些源似乎为空(0字节),并且屏幕上未显示任何内容。以下是结果的屏幕截图以及Django调试栏中的“静态文件”标签的屏幕截图。
有人知道为什么它无法在Django中正确提供这些文件吗?
[编辑]
我刚刚发现如果我改变
STATIC_URL = '/static/'
到
STATIC_URL = '/'
当我转到http://127.0.0.1:8000/index.html
时它可以正常工作,但是现在http://127.0.0.1:8000/
给了我这个错误:
[编辑2]
好,所以按照@geek_life的建议,我将设置文件中的值更改为:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_NAME = 'cockpit'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, PROJECT_NAME, "static/")
STATICFILES_DIRS = [os.path.join(BASE_DIR, '../frontend/dist')]
print("## BASE_DIR:", BASE_DIR)
print("## STATIC_ROOT:", STATIC_ROOT)
print("## STATICFILES_DIRS:", STATICFILES_DIRS)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['cockpit/static/'], # <= THIS IS WHAT I CHANGED
'APP_DIRS': True,
'OPTIONS': {} # And here some options
},
]
哪个打印出来
## BASE_DIR: /home/kramer65/repos/cockpit/backend
## STATIC_ROOT: /home/kramer65/repos/cockpit/backend/cockpit/static/
## STATICFILES_DIRS: ['/home/kramer65/repos/cockpit/backend/../frontend/dist']
在文件settings/urls.py
中,我(仍然)得到了这个信息:
urlpatterns = [
path('admin/', admin.site.urls),
path('cockpit/', include("cockpit.urls")),
re_path('', TemplateView.as_view(template_name='index.html')),
]
然后我将带有内置vuejs-ap的static/
文件夹从cockpit/backend/
复制到cockpit/backend/cockpit/
。
不幸的是,我仍然得到相同的结果。 index.html已加载,但js和css文件仍然没有加载。还有其他想法吗?
答案 0 :(得分:3)
第一种情况
STATIC_URL = '/static/'
只有在URL带有backend/static/
的情况下,例如,例如,Django会尝试在/static/
文件夹中查找静态文件。在您的/static/css/*
中提到了/static/js/*
或index.html
,但是这里的情况并非如此index.html
像/css/*
和/js/*
这样的文件引用,因此找不到它们。
此案例在Blog示例中起作用的原因是由于相同的原因,即它们的模板文件保存在'../frontend/build
目录下,而静态文件位于'../frontend/build/static'中,因此{ {1}}将寻找index.html
而不是static/js/*
,因此/js/*
的网址位置是在Django中访问的,然后Django会正确地在/static/
中查找文件
这就是在您的代码中将其设置为第二种情况的原因,即
backend/static
将静态文件的网址正确地定位到STATIC_URL = '/'
和/css/*
,甚至您的/js/*
也可以被视为静态文件,即所有这些网址都被认为是静态的,并在/index.html
文件夹,因此在浏览器中正确显示。
但是现在这些URL混乱了,即:
backend/static/
可以将视为Django寻找以下位置:re_path('', TemplateView.as_view(template_name='index.html')),
,但是它已经保留用于搜索静态文件,并且在/
之后不包含任何文件名意味着您没有在寻找任何文件。
Django允许自定义网址格式,即您可以在settings.py中创建2个新变量。
/
然后配置您的urls.py
STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
STATIC_JS_URL = "/js/"
STATIC_JS_ROOT = os.path.join(STATIC_ROOT, "js/")
STATIC_CSS_URL = "/css/"
STATIC_CSS_ROOT = os.path.join(STATIC_ROOT, "css/")
答案 1 :(得分:2)
我很久以前就有这个问题,所以我用一个简单的解决方案解决了。 太简单了。 如我所见,您的静态文件夹不在您的应用程序根目录中,并且放置在错误的位置。 将其放在您的应用程序根目录中...因为Django正在应用程序的主根目录中查找静态文件夹,其中的views.py在那里。 也许您有5个或更多应用程序。 Django并不关心您拥有的应用程序数量,Django只会在应用程序根目录中查找您的静态文件夹。 但是您的模板文件夹可以在您的项目根目录中。 因此,将您的静态文件夹放在您的应用程序根目录中。 在这种情况下,我的意思是在驾驶舱内。
然后您必须在settings.py中添加此更改
PROJECT_NAME = '---Your projects name---'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, PROJECT_NAME, 'static/')
EXTERNAL_APPS = [
'django.contrib.staticfiles',
]
祝你好运。
答案 2 :(得分:1)
STATIC_URL
首先,STATIC_URL
将是静态文件will be served的URL。因此,如果您设置STATIC_URL='/'
然后导航至http://127.0.0.1:8000/index.html
,它将基本上从Django应用程序的静态文件夹中服务index.html
。如果转到http://127.0.0.1:8000/
,则位于“静态文件夹根目录”,并且如您所见,目录索引被禁止。所以不要使用STATIC_URL='/'
您遵循的教程将SPA的build文件夹添加到Django settings.py
文件中的模板中。
所以您应该尝试添加:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(os.path.dirname(BASE_DIR), 'frontend', 'dist')], # <== ADDED THIS
'APP_DIRS': True,
'OPTIONS': {
# removed to keep this example small
},
]
,或者如果您要指向静态文件作为模板目录:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'static')],
'APP_DIRS': True,
'OPTIONS': {
# removed to keep this example small
},
]
但是,我认为这不是最佳实践,因为静态文件(图像,JS,CSS)在Django中具有自己的限定条件。
os.path
的注意另外,对于您的STATICFILES_DIRS
,os.path.join()
works也不这样。第一个参数应该是您要与一个或多个路径组件连接的路径,然后这些组件将作为下一个参数传递。此外,BASE_DIR
不在正确的目录级别,如打印出BASE_DIR
路径时所见。您需要BASE_DIR
目录的父目录。要获取parent directory的路径,可以执行os.path.dirname(BASE_DIR)
,因为BASE_DIR
是路径。因此,应用此我们得到:
STATICFILES_DIRS = [
os.path.join(os.path.dirname(BASE_DIR), frontend, dist),
]
我确实认为让SPA为您提供SPA服务而不将其完全包含在Django BASE_DIR
中(因此,其名称为基本目录)可能是一种反模式。但是我不知道它的来源,或者确切地如何最佳实践。
答案 3 :(得分:0)
第一件事!如果要将Django的UI作为生产的静态文件提供,这是个坏主意!您需要考虑使用nginx或类似的Web服务器为您提供静态文件。
您的TemplateView
中的urls.py
有点问题。由于在您的第一种情况下,您的静态文件位于STATIC_URL = '/static/'
下,因此js和CSS文件的网址不匹配。您可以编辑文件,并将static
模板标签放入index.hml
内,但这也不是一个好主意。当您在vuejs方面进行更改时,您需要直接构建和替换该包,并且您的网站也会更新。因此,需要永久删除此行,必须将index.html视为静态文件:
re_path('', TemplateView.as_view(template_name='index.html')),
更改STATIC_URL = '/'
后,您可以访问所有静态文件。如果您在debug = True
中运行django,它将自动提供静态文件。否则,您需要将静态url conf添加到文件中。 (不要忘记,这对生产不利!)
from django.contrib import admin
from django.urls import include, path, re_path
from django.views.generic import TemplateView
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('cockpit/', include("cockpit.urls")),
]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
使用此设置,您需要注意您的URL和静态文件命名。它们可能会相互覆盖。
P.S:谢谢你这么详细的问题。
答案 4 :(得分:0)
有一种愚蠢的方法可以解决此问题。
此问题与VueJS构建的html将从诸如/js/app.12312sd.js
和/css/app.dsfeewj.css
这样的路径中获取js和css一样。
静态文件根路径的默认设置为/static/
,因此您只需要手动更改/js/...
中的每个/css/...
和index.html
或使用sed
或还有其他东西可以将它们替换为/static/js/.../
和/static/css/.../
。
您无法将STATIC_URL
替换为/
,因为它是您网站的根网址。
编辑后,它将看起来像这样,然后将您的django服务器作为服务器运行即可。
答案 5 :(得分:0)
在构建前端之前,将css /和js /放在名为“ static”的目录中,并保持index.html不变。然后,当您运行yarn build
时,目录结构如下-
cockpit
├── backend/
│ ├── cockpit/
│ │ ├── views.py
│ │ ├── css/
│ │ └── etc..
│ ├── settings/
│ │ └── settings.py
│ └── manage.py
└── frontend/
└── dist/
├── static/
│ ├── css/
│ └── js/
└── index.html
设置您的BASE_DIR和FRONTEND_DIR指向“驾驶舱/前端/ dist”,以便稍后使用。
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
FRONTEND_DIR = os.path.join(os.path.dirname(BASE_DIR),'frontend','dist')
现在,您可以像以前一样将前端静态文件复制到后端目录中-
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(FRONTEND_DIR,'static/'),
]
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
或者您可以直接将后端指向要从内置的前端目录提供服务,而不必再次复制它。 (我总是这样)
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(FRONTEND_DIR,'static/')
在模板目录中包含构建的前端目录,以便Django可以提供index.html
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [FRONTEND_DIR],
'APP_DIRS': True,
'OPTIONS': {
# removed to keep this example small
},
},
]
现在运行服务器
$ python manage.py collectstatic
$ python manage.py runserver
如果以后您决定在线部署此文件,则可以通过将Nginx设置为从静态目录中提供静态文件来轻松使用此配置本身。 希望这会有所帮助:)
消除您对[编辑]的困惑
STATIC_ROOT指向系统上的目录。 STATIC_URL指的是在使用您的网站时访问STATIC_ROOT中存在的静态文件的URL。
假设您的目录中有一个script.js文件,如图所示
cockpit
├── backend/
│ ├── cockpit/
│ │ ├── views.py
│ │ ├── css/
│ │ └── etc..
│ ├── settings/
│ │ └── settings.py
│ └── manage.py
└── frontend/
└── dist/
├── static/
│ ├── css/
│ └── js/
│ └── script.js
└── index.html
并且您已将STATIC_ROOT设置为指向“驾驶舱/前端/ dist /静态/”。
现在,如果您将STATIC_URL设置为“静态/”,则可以在http://127.0.0.1:8000/static/js/script.js上访问该脚本
或者,如果您将STATIC_URL设置为“ xcsdf /”,则可以在http://127.0.0.1:8000/xcsdf/js/script.js上访问js文件