2

My application sits at the server path /home/myapp/.

The static assets sit at /home/myapp/src/static/ when a python manage.py collectstatic is performed.

It copies assets from /home/myapp/src/assets/.

I have tried with DEBUG both True and False.

When I navigate to the web application at https://test.example.com, it tells me that all of the assets that reside at /home/mpapp/src/assets/ are 404 (Not Found) despite the files being there.

Also, my web server setup is Apache with a reverse proxy to Gunicorn. I'm serving the application with gunicorn wsgi which serves the application at 127.0.0.1:8000, which is where Apache is ProxyPass to. I've tested against a brand new Django application and this setup serves it properly, so it shouldn't be how Apache and Gunicorn are configured.

What I have been doing is:

1) npm start to compile the React front-end assets

2) python manage.py collectstatic to move the assets to /static/

3) Run gunicorn wsgi where the manage.py and wsgi.py reside

Some code would be helpful. Here is my settings.py:

import os
import sys
import json
import datetime

from unipath import Path
from django.core.exceptions import ImproperlyConfigured

# Import JSON file 
print(Path(__file__))
with open('./config/config.json') as f:
    s = json.loads(f.read())

def get_settings(settings, s=s):
    try:
        return s[settings]
    except KeyError:
        error_msg = 'Set the {0} environment vaiable'.format(settings)
        raise ImproperlyConfigured(error_msg)


# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = Path(__file__).ancestor(2)


# Quick-start development settings - unsuitable for production

# SECURITY WARNING: keep the secret key used in production secret! 
SECRET_KEY = get_settings('SECRET_KEY')


ALLOWED_HOSTS = [
    '*',
]

# Application definition

INSTALLED_APPS = [
    # Base packages
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Third party packages
    'rest_framework',
    'rest_framework_jwt',
    'webpack_loader',
    'tinymce',

    # Local packages
    'authentication',
    'documents',
    'contact',
    'home',
    'results',
    'users'
]

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

ROOT_URLCONF = 'config.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, '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',
            ],
        },
    },
]


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

WSGI_APPLICATION = 'wsgi.application'


# Password validation
AUTH_USER_MODEL = 'authentication.User'

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',
    },
]


# REST Framework settings
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
         'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
}


# DRF JWT token settings
JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
    'JWT_ALLOW_REFRESH': True,
}


# Webpack settings
WEBPACK_LOADER = {
    'DEFAULT': {
        'BUNDLE_DIR_NAME': 'bundles/',
        'STATS_FILE': os.path.join(BASE_DIR, './config/webpack-stats.json'),
    }
}


STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'assets'),
)

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

# Static files (CSS, JavaScript, Images)

STATIC_URL = '/static/'


# Internationalization

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'America/Los_Angeles'

USE_I18N = True

USE_L10N = True

USE_TZ = False


# EMAIL SETTINGS

EMAIL_HOST = get_settings('EMAIL_HOST')

EMAIL_HOST_USER = get_settings('EMAIL_HOST_USER')

EMAIL_HOST_PASSWORD = get_settings('EMAIL_HOST_PASSWORD')

EMAIL_PORT = get_settings('EMAIL_PORT')

EMAIL_USE_TLS = True

My directory structure looks like the following which is based on Two Scoops:

testapp
    assets
        bundles
            css
                app.e1c352f1.css
            js
                vendor.s63d4f.js
                manifrest.5fd4g.js
                app.dsr5h4.js
        css
            bootstrap.css
        img
        scss
    config
         config.json
         settings.py
         urls.py
         webpack.config.js
    react
         index.jsx
    static
         admin
         bundles
             css
                app.e1c352f1.css
             js
                vendor.s63d4f.js
                manifrest.5fd4g.js
                app.dsr5h4.js
         css
             bootstrap.css
         img
         rest_framework
         scss
    templates
         index.html
    manage.py
    wsgi.py

Also, my urls.py if that might be relevant:

from django.conf.urls import url, include
from django.contrib import admin
from django.views.generic.base import TemplateView

from home.views import GetHomeAPIView

    urlpatterns = [
        # Admin URL
        url(r'^admin', admin.site.urls),

        # API authentication entry point   
        url(r'^api/auth/', include('authentication.urls', namespace='signin')),

        # API /home entry point   
        url(r'^api/home/', GetHomeAPIView.as_view(), name='home'),

        # API /contact entry point   
        url(r'^api/contact/', include('contact.urls', namespace='contact')),

        # API /contact entry point   
        url(r'^api/users/', include('users.urls', namespace='users')),

        # Any requets that come through serve the index.html
        url(r'^$', TemplateView.as_view(template_name='index.html')),
    ]

So not sure 100% what to do.

I have tried changing both STATIC_ROOT and STATIC_URL to the actual path /home/myapp/src/static/ which didn't do anything.

A bit stumped as to how to resolve this and the SO questions I have reviewed have not fixed the issue.

cjones
  • 8,384
  • 17
  • 81
  • 175
  • I think you want to set up as described in https://librenepal.com/article/django-and-create-react-app-together-on-heroku/ and https://stackoverflow.com/questions/64752743/django-on-heroku-missing-staticfiles-manifest-json-file – dfrankow Oct 17 '21 at 17:59

1 Answers1

1

Well, I got things to start loading by doing the following in urls.py:

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

urlpatterns = [
    # ... the rest of your URLconf goes here ...
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

Also can be read about here.

https://docs.djangoproject.com/en/dev/howto/static-files/#serving-static-files-during-development

It is working, but that being said, the sections is called "Serving static files during development"... I'm doing this for production.

cjones
  • 8,384
  • 17
  • 81
  • 175