Django - 部署后只有一些静态图像没有显示在网页上

Posted

技术标签:

【中文标题】Django - 部署后只有一些静态图像没有显示在网页上【英文标题】:Django - Only some static images not showing up on web page after deployment 【发布时间】:2020-09-24 05:17:17 【问题描述】:

所以我在设置下设置了我的静态网址:

settings.py

STATIC_URL = '/static/'


if DEBUG or not DEBUG:
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, 'tabular', 'templates'),
        os.path.join(BASE_DIR, 'common'),
    )

那么这里是我的静态文件文件夹路径

我有一个带有 logo.png 和 step1.png-step4.png 的网页。由于某些奇怪的原因,当我在部署中运行时,它正确获取 logo.png,但不是 step1.png-step4.png。

这里是html代码。

<div id="wrapper">
  <div id="container">
    <img style="padding: 1em;" src="% static 'images/logo.png' %" />
    <form
      class="form-horizontal"
      enctype="multipart/form-data"
      id="data_upload"
      method="POST"
    >
      % csrf_token %
      <div class="input-group mb-3">
        <div class="custom-file">
          <input
            accept=".csv"
            class="custom-file-input"
            id="file_input"
            name="file"
            type="file"
          />
          <label
            aria-describedby="inputGroupFileAddon02"
            class="custom-file-label"
            for="inputGroupFile02"
            id="submit_label"
            >Upload CSV</label
          >
        </div>
        <div class="input-group-append">
          <button
            class="input-group-text btn"
            id="upload_button"
            type="submit"
            disabled
          >
            Upload
          </button>
        </div>
      </div>
      <div id="progress_div" class="progress" style="visibility: hidden;">
        <div
          id="progress_bar"
          class="progress-bar"
          role="progressbar"
          style="width: 0%;"
          aria-valuenow="25"
          aria-valuemin="0"
          aria-valuemax="100"
        ></div>
      </div>
      <br />
      <div
        id="spinner"
        class="d-flex justify-content-center"
        style="visibility: hidden;"
      >
        <div class="spinner-border text-primary" role="status">
          <span class="sr-only">Loading...</span>
        </div>
      </div>
    </form>
  </div>
</div>

<div
  class="modal fade"
  id="my_modal"
  tabindex="-1"
  role="dialog"
  data-target="#my_modal"
  aria-labelledby="exampleModalLabel"
  aria-hidden="true"
>
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="modal_title">Modal title</h5>
        <button
          type="button"
          class="close"
          data-dismiss="modal"
          aria-label="Close"
        >
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div id="modal_body" class="modal-body"></div>
    </div>
  </div>
</div>

<div
  class="modal fade"
  id="how_to_modal"
  tabindex="-1"
  role="dialog"
  data-target="#how_to_modal"
  aria-hidden="true"
>
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="modal_title">How To</h5>
        <button
          type="button"
          class="close"
          data-dismiss="modal"
          aria-label="Close"
        >
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <div
          id="carouselExampleCaptions"
          class="carousel slide"
          data-ride="carousel"
        >
          <ol class="carousel-indicators" style="color: black;">
            <li
              data-target="#carouselExampleCaptions"
              data-slide-to="0"
              class="active"
            ></li>
            <li data-target="#carouselExampleCaptions" data-slide-to="1"></li>
            <li data-target="#carouselExampleCaptions" data-slide-to="2"></li>
            <li data-target="#carouselExampleCaptions" data-slide-to="3"></li>
          </ol>
          <div class="carousel-inner">
            <div class="carousel-item active">
              <img
                src="% static 'imgs/step1.png' %"
                class="d-block w-100"
                
              />
            </div>
            <div class="carousel-item">
              <img
                src="% static 'imgs/step2.png' %"
                class="d-block w-100"
                
              />
            </div>
            <div class="carousel-item">
              <img
                src="% static 'imgs/step3.png' %"
                class="d-block w-100"
                
              />
            </div>
            <div class="carousel-item">
              <img
                src="% static 'imgs/step4.png' %"
                class="d-block w-100"
                
              />
            </div>
          </div>
          <a
            class="carousel-control-prev"
            href="#carouselExampleCaptions"
            role="button"
            data-slide="prev"
          >
            <span class="carousel-control-prev-icon" aria-hidden="true"></span>
            <span class="sr-only">Previous</span>
          </a>
          <a
            class="carousel-control-next"
            href="#carouselExampleCaptions"
            role="button"
            data-slide="next"
          >
            <span class="carousel-control-next-icon" aria-hidden="true"></span>
            <span class="sr-only">Next</span>
          </a>
        </div>
      </div>
    </div>
  </div>
</div>

问题 这是 Google Chrome 开发人员中控制台打印的内容

GET https://blackboxml.cs.ubc.ca/static/imgs/step1.png 404 (Not Found)   
GET https://blackboxml.cs.ubc.ca/static/imgs/step2.png 404 (Not Found)  
GET https://blackboxml.cs.ubc.ca/static/imgs/step3.png 404 (Not Found)  
GET https://blackboxml.cs.ubc.ca/static/imgs/step4.png 404 (Not Found)  

当我以调试模式在我的个人窗口上运行此程序时,图像可以正常显示。另一个奇怪的事情是 html 的 css 在同一个文件夹中,但是可以正确加载但不是 pngs。

ls -l

-rw-r----- 1 virtuecc fwood 52176 Jun  4 16:27 step1.png
-rw-r----- 1 virtuecc fwood 32364 Jun  4 16:27 step2.png
-rw-r----- 1 virtuecc fwood 38267 Jun  4 16:27 step3.png
-rw-r----- 1 virtuecc fwood 49833 Jun  4 16:27 step4.png

其他文件

-rw-r----- 1 virtuecc fwood 9727 May 28 15:30 logo.png

我的尝试 - 我将所有 png 文件放在同一个文件夹“common/images”中,但仍然只有 logo.png 成功获取。 - 我还被告知运行命令“python manage.py collectstatic”应该可以解决这个问题。我从“https://www.youtube.com/watch?v=m0zEz_qdPLY”得到这个提示

规格 - Web 服务器是 Ubuntu - Django 3.0.7 - Python 3.6.9

谁能告诉我为什么会这样?最终目标只是在部署期间为网站提供静态数据,如果有更好的方法可以做到这一点,我也愿意接受建议。

【问题讨论】:

您的 imgs 目录是模板目录的子目录,但您在 HTML 中的路径不包括模板目录。 它不应该要求这样做,因为父目录是静态的。据我所知,当您添加静态路径时,它充当包含所有静态文件的文件夹。此外,当我在我的个人窗口上调试时运行它而不是在开发中时,它们加载得很好。 @Roy2012 是的,我做到了,这不是一个愚蠢的问题,而是一个非常合理的问题,人为错误通常是导致事情无法正常工作的原因。我希望在这种情况下,更多的是我不知道 Django 对人为错误的规则 还有一个问题 - 因为您将所有图像放在一个目录中,所以有些工作,有些不工作,也许这是一个部署问题?您是否验证了所有文件都进入了 prod。环境,有适当的权限等? 您介意对有效的图像运行相同的“ls -l”吗(在 images 和 img 目录下)? 【参考方案1】:

问题:

您的django.contrib.staticfiles 应用只能在DEBUG 模式下运行。

提供静态文件shown here的另一种开发方法也只适用于DEBUG模式。

注意:此帮助函数仅在调试模式下有效,并且仅当给定前缀是本地前缀(例如 /static/)而不是 URL(例如 http://static.example.com/)时才有效。

此外,此辅助函数仅服务于实际的 STATIC_ROOT 文件夹;它不像 django.contrib.staticfiles 那样执行静态文件发现。


推荐解决方案:

您想要(和需要)生产的东西是在部署和设置服务 /absolute/path/to/static/ 后运行 collectstatic 在您的 nginx/apache conf 中描述 here 和 here :)


替代方案:

如果您出于某种原因不想通过 NGINX/Apache 使用静态文件服务,或者如果您计划在未来使用 CDN 服务,您可能会对使用 whitenoise 感兴趣:http://whitenoise.evans.io/en/stable/django.html

【讨论】:

我实际上已经关闭了调试模式。这绝对是我考虑过的事情。这可能导致它的调试模式关闭,理论上它应该阻止所有静态文件,但是徽标不应该出现,但确实如此。 是的,标志很奇怪。您是否通过开发人员工具检查了“禁用缓存”以排除浏览器缓存?我还有一个案例,徽标和网站图标在 nginx 规则中是硬连线的:)【参考方案2】:
    当您开发项目时,您使用了python manage.py runserver。它启动了开发服务器。所以它从获取静态文件
if DEBUG or not DEBUG:
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, 'tabular', 'templates'),
        os.path.join(BASE_DIR, 'common'),
    )

但是生产服务器以不同的方式工作。它从网络服务器(apache or nginx) 获取文件。所以你必须像这样配置你的网络服务器。

server 

    listen  8000;
    server_name test.com;

    client_max_body_size 4G;

    access_log /home/shubham/aconitedata/aconitedata/logs/nginx-access.log;
    error_log /home/shubham/aconitedata/aconitedata/logs/nginx-error.log;

   location /static/ 
       alias   /home/shubham/aconitedata/aconitedata/aconite/aconite/static/;
   

   location /media/ 
        alias  /home/shubham/aconitedata/aconitedata/aconite/aconite/media/;
   

   location / 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;

       # Try to serve static files from nginx, no point in making an
       # *application* server like Unicorn/Rainbows! serve static files.
       if (!-f $request_filename) 
            proxy_pass http://aconite_server;
           break;
       
   


    我在屏幕截图中看到了您的目录结构。静态文件有两种不同的路径。

您的logo.png 已提取,因为可能在您的网络服务器中为该目录设置了静态路径。您必须在网络服务器中设置多个静态路径。

Suggestion - 使用相同的静态路径。并借助 collectstatic 管理多个应用的​​静态目录。

这就是 collectstatic 在一个地方管理所有应用程序静态文件的方式。然后,我在 webserver 中设置了这个静态目录路径。

【讨论】:

【参考方案3】:

在一切正常之前,我已尝试修复 Web 应用程序中的一些错误。 文件夹的配置,没有引起任何问题的是在主项目目录中使用source 文件夹,其中包含整个项目的staticfilestemplates 文件夹。另外,在每个应用程序文件夹中,包含一个名为 templates 的文件夹,这仅对特定应用程序是必需的。像这样的:

project_dir/
     source_dir/
            app_dir/
                 templates/
                      app_dir/
                           template.html
            app_dir/
                  templates/
                      app_dir/
                           template.html
            staticfiles/
            templates/
                 template.html
            project_dir/
                  manage.py
      static_cdn_dir/
            media/
            static/

settings.py 文件中的变量设置如下:

STATIC_URL = '/static/'
STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'staticfiles')]

可能还有其他变量需要设置,比如STATIC_ROOT and MEDIA_ROOT;如果有mediastatic这样的目录,应该使用这些变量,类似于STATICFILES_DIRS var,只是路径不一样:

STATIC_ROOT = os.path.join(LOCAL_STATIC_CDN_PATH, 'static') 
MEDIA_ROOT = os.path.join(LOCAL_STATIC_CDN_PATH, 'media')

LOCAL_STATIC_CDN_PATH 也必须设置:

LOCAL_STATIC_CDN_PATH = os.path.join(os.path.dirname(BASE_DIR), 'static_cdn_dir')

静态文件需要被 Django 引用,这意味着 javascript、CSS 和图像必须链接到 Django。 STATIC_ROOT var 代表一个 live cdn,这就是使用 var LOCAL_STATIC_CDN_PATH 设置它的原因。所以在这种情况下,static_cdn_dir 被用来代替静态服务器。

通常,settings.py 中的变量是根据 Web 应用程序的类型、其中使用的技术、目录树的配置以及项目是否处于测试阶段的情况来设置的。

【讨论】:

【参考方案4】:

我为在生产模式或 DEBUG=FALSE 时加载的媒体文件和静态文件找到的一种解决方案

首先添加下面的代码或导入上面的urls.py文件。

从 django.views.static 导入服务

然后,在您的 URL 模式下面添加行,

如果不是 settings.DEBUG: urlpatterns += [ url(r'^uploads/(?P.)$', serve,'document_root': settings.MEDIA_ROOT), url(r'^static/(? P.)$', serve,'document_root': settings.STATIC_ROOT), ]

希望这会有所帮助!

Source

【讨论】:

【参考方案5】:

在这种情况下,它是由linux中的目录读取和执行权限问题引起的。所以解决方法是使用chmod命令来改变相关目录和文件的权限。

# To recursively give directories read&execute privileges:
$ find /path/to/base/dir -type d -exec chmod 755  +
# To recursively give files read privileges:
$ find /path/to/base/dir -type f -exec chmod 644  +
# Or, if there are many objects to process:
$ chmod 755 $(find /path/to/base/dir -type d)
$ chmod 644 $(find /path/to/base/dir -type f)
# Or, to reduce chmod spawning:
$ find /path/to/base/dir -type d -print0 | xargs -0 chmod 755 
$ find /path/to/base/dir -type f -print0 | xargs -0 chmod 644

浏览博客:https://gist.github.com/douglasmiranda/2153f15a6581ef676f6dee7ac5584874

【讨论】:

【参考方案6】:

首先,如果调试关闭,则提供的静态文件处理程序不会提供静态文件,无论您是否明确告诉它这没关系。这是因为提供静态文件是一个巨大的安全问题,并且开发人员不希望它对您来说那么容易做到这一点(提供文件充满危险,并且是一个难题,经过多年的全面实施的 Web 服务器已经有效地解决了安全漏洞修补,而 Django 开发人员不会为开发服务器做这些)。这是来自 Django 的相关代码:

def static(prefix, view=serve, **kwargs):
    """
    Return a URL pattern for serving files in debug mode.

    from django.conf import settings
    from django.conf.urls.static import static

    urlpatterns = [
        # ... the rest of your URLconf goes here ...
    ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    """
    if not prefix:
        raise ImproperlyConfigured("Empty static prefix not permitted")
    elif not settings.DEBUG or urlsplit(prefix).netloc:
        # No-op if not in debug mode or a non-local prefix.
        return []
    return [
        re_path(r'^%s(?P<path>.*)$' % re.escape(prefix.lstrip('/')), view, kwargs=kwargs),
    ]

如果你真的不在乎安全,你可以这样做:

def static(prefix, view=serve, **kwargs):
    """
    Version of the static views that DOESN'T check for the DEBUG flag since we're
    checking it elsewhere and static items are needed for e2e tests.

    NOTICE: Sometimes the Staticfiles app decides to do whatever it wants and then
    reports this view was the one that did it. If you can't print from the serve
    function, it's full of shit. Check the STATICFILES_DIRS instead.
    """
    if not prefix:
        raise ImproperlyConfigured("Empty static prefix not permitted")
    elif '://' in prefix:
        # No-op if not in debug mode or a non-local prefix.
        return []
    return [
        url(r'^%s(?P<path>.*)$' % re.escape(prefix.lstrip('/')), view, kwargs=kwargs),
    ]

urlpatterns += static('/static/', document_root=settings.STATIC_ROOT)

...或类似的。但是,如果此服务器有可能暴露于开放的 Internet,您应该学习如何使用静态文件处理进行正确的部署配置。这是有关如何在 Ubuntu 上使用通用设置执行此操作的指南:https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-16-04。版本有点旧,但应该很接近,可以让你朝着正确的方向前进。

【讨论】:

以上是关于Django - 部署后只有一些静态图像没有显示在网页上的主要内容,如果未能解决你的问题,请参考以下文章

不允许在/空静态前缀处配置不当 - Django

在 Django 模型中显示静态图像

Django显示静态文件夹之外的图像/视频

调试模式打开时的 Django 和静态文件

django项目部署后静态文件收集解决admin后台静态文件丢失

在 Heroku 服务器上部署 Django 错误 (500) - 据说是静态文件问题