Django - Only some static images not showing up on web page after deployment

Viewed 4118

So I have my static url set as such under settings:

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'),
    )

Then here is my folder path with the static files

enter image description here

I have a webpage with logo.png and step1.png-step4.png. For some odd reason when I'm running in deployment, it correct fetches logo.png, but not step1.png-step4.png.

Here is the html code.

<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"
                alt="..."
              />
            </div>
            <div class="carousel-item">
              <img
                src="{% static 'imgs/step2.png' %}"
                class="d-block w-100"
                alt="..."
              />
            </div>
            <div class="carousel-item">
              <img
                src="{% static 'imgs/step3.png' %}"
                class="d-block w-100"
                alt="..."
              />
            </div>
            <div class="carousel-item">
              <img
                src="{% static 'imgs/step4.png' %}"
                class="d-block w-100"
                alt="..."
              />
            </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>

Problem
Here's what console prints in Google Chrome dev

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)  

When I run this on my personal windows in debug mode, the images display properly. Also another weird thing is the css for the html is in the same folder, but that gets loaded properly but not the 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

Other file

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

What I've tried
- I put all the pngs in the same folder 'common/images' and still only logo.png got fetched successfully.
- I was also told running the command "python manage.py collectstatic" should fix this. I got this tip off "https://www.youtube.com/watch?v=m0zEz_qdPLY"

Specifictations
- Web server is Ubuntu
- Django 3.0.7
- Python 3.6.9

Can anyone tell me why this is happening? The ultimate goal is just to serve the statics to the website during deployment if there's a better way to do this I'm open to suggestions as well.

6 Answers

The problem:

Your django.contrib.staticfiles app only works in DEBUG mode.

The other development method to serve static files shown here also only works in DEBUG mode.

Note: This helper function works only in debug mode and only if the given prefix is local (e.g. /static/) and not a URL (e.g. http://static.example.com/).

Also this helper function only serves the actual STATIC_ROOT folder; it doesn’t perform static files discovery like django.contrib.staticfiles.


Recommended solution:

What you want (and need) for production is running collectstatic after deployment and setup serving /absolute/path/to/static/ in your nginx/apache conf described here and here :)


The alternative:

If you, for whatever reason, don't want to use static file serving via NGINX/Apache or if you plan to use a CDN service in the upcoming future you might be interested in using whitenoise: http://whitenoise.evans.io/en/stable/django.html

  1. When you developing the project you used python manage.py runserver. It's start the development server. So it takes the static files from
if DEBUG or not DEBUG:
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, 'tabular', 'templates'),
        os.path.join(BASE_DIR, 'common'),
    )

But production server works in different way. It takes files from web server (apache or nginx). So you have to configure your web-server like.

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;
       }
   }
}

  1. I saw your directory structure in screenshot. There are two different path for static files.

Your logo.png fetched, because may be in your web server static path is set for that directory. You have to set multiple static path in webserver.

Suggestion - Used same static path. And by the help of collectstatic manage the multiple app static directory.

enter image description here

This is how collectstatic manage all app static file in one place. Then, I set this static directory path in webserver.

I have tried to fix some bugs into web applications, before everything worked just well. The configuration of the folders, one that didn't cause any problems is this to use a source folder inside the main project directory, and there to include the staticfiles and the templates folder for the entire project. And separately, inside each app folder, to include a folder named templates, that is necessary only for a specific app. Something like this:

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/

The variables in the settings.py file were set like this:

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

There may be other variables that need to be set, like STATIC_ROOT and MEDIA_ROOT; if there are directories like media and static, these variables should be used, similar to the STATICFILES_DIRS var, except that the path is not the same:

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

and the LOCAL_STATIC_CDN_PATH has to be set as well:

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

Static files need to be referenced by Django meaning that the Javascript, CSS and images have to be linked into Django. The STATIC_ROOT var represents a live cdn and this is why it is set using the var LOCAL_STATIC_CDN_PATH. So in this case, the static_cdn_dir is used in the place of a static server.

Usually, the variables in settings.py are set taking into consideration the type of web application, the technologies used in it, the configuration of the directory tree and depending on the situation if the project is in the test phase or not.

One Solution I found for the media files & the static files load in production mode or when DEBUG=FALSE

First Add below code or Import above of urls.py file.

from django.views.static import serve

Then, Add the Lines below of your URL Patterns,

if not settings.DEBUG: urlpatterns += [ url(r'^uploads/(?P.)$', serve,{'document_root': settings.MEDIA_ROOT}), url(r'^static/(?P.)$', serve,{'document_root': settings.STATIC_ROOT}), ]

Hope this helps!

Source

in the case, its raised by directories read and execute priviledge problem in linux. So the solution is using chmod command to change priviledage of the related directories and files.

# 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

go through the blog: https://gist.github.com/douglasmiranda/2153f15a6581ef676f6dee7ac5584874

First off, if debug is off, the provided static files handler does not serve static files, REGARDLESS OF WHETHER OR NOT YOU HAVE EXPLICITLY TOLD IT THAT THIS IS OK. This is because serving static files is a massive security issue and the devs did not want it to be so easy for you to do this (serving files is fraught with peril and is a hard problem that fully implemented web servers have effectively solved after years of security hole patching, and which the Django devs aren't going to do for a dev server). Here's the relevent code from 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),
    ]

You could, if you really don't give a crap about security, do it this way:

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)

...or similar. But you should, instead, learn how to do a proper deployment configuration with static files handling if there's any chance this server will be exposed to the open internet. Here is a guide on how to do this with a common setup on Ubuntu: https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-16-04 . The version's a bit old but this should be pretty close and put you in the right direction.

Related