DJango admin is serving static files from /media instead of /static - django

When I run my django app in production mode (ie without DEBUG), my admin site tries to serve static files from "/media" instead of "/static", which causes 404s
This is what it's trying to serve.
GET https://<domain>/media/admin/css/base.css
But if I manually type in
https://<domain>/static/admin/css/base.css
It serves the static file correctly. So my "collectstatic" is working fine, but somehow the admin site is trying to serve from /media.
I don't understand what settings would cause this. Everything I search for related to this is from before django 1.4 where there was a specific setting for admin media url. Other than that I don't see anyone else having this issue.
I'm loosely following https://github.com/cookiecutter/cookiecutter-django and I'm on the latest version of django right now. I'm not sure what else to look for
A selection of settings (presumably irrelevant ones omitted)
#config/settings/base.py
DJANGO_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.sites",
"django.contrib.messages",
"django.contrib.staticfiles",
# "django.contrib.humanize", # Handy template tags
"django.forms",
]
# STATIC
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#static-root
STATIC_ROOT = str(ROOT_DIR / "staticfiles")
# https://docs.djangoproject.com/en/dev/ref/settings/#static-url
STATIC_URL = "/static/"
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
STATICFILES_DIRS = [str(APPS_DIR / "static")]
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders
STATICFILES_FINDERS = [
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
]
# MEDIA
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#media-root
MEDIA_ROOT = str(APPS_DIR / "media")
# https://docs.djangoproject.com/en/dev/ref/settings/#media-url
MEDIA_URL = "/media/"
# TEMPLATES
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#templates
TEMPLATES = [
{
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND
"BACKEND": "django.template.backends.django.DjangoTemplates",
# https://docs.djangoproject.com/en/dev/ref/settings/#dirs
"DIRS": [str(APPS_DIR / "templates")],
# https://docs.djangoproject.com/en/dev/ref/settings/#app-dirs
"APP_DIRS": True,
"OPTIONS": {
# https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.template.context_processors.i18n",
"django.template.context_processors.media",
"django.template.context_processors.static",
"django.template.context_processors.tz",
"django.contrib.messages.context_processors.messages",
"moment.users.context_processors.allauth_settings",
],
},
}
]
--
#config/settings/production.py
from .base import * # noqa
from .base import env
STATICFILES_STORAGE = "django.core.files.storage.FileSystemStorage"
COLLECTFAST_STRATEGY = "collectfast.strategies.filesystem.FileSystemStrategy"
ADMIN_URL = env("DJANGO_ADMIN_URL")
# Collectfast
# ------------------------------------------------------------------------------
# https://github.com/antonagestam/collectfast#installation
INSTALLED_APPS = ["collectfast"] + INSTALLED_APPS # noqa F405
Note that most of the static file settings are declared in my base.py, which is included when I run this in "debug" mode using config/settings/local.py. And that works fine. It's only in production mode that it's trying to serve the static files out of /media

It turns out this was caused by the https://github.com/antonagestam/collectfast provided by the cookiecutter template I was using. The default tried to use s3 as the static file location, and I configured it to use the local filesystem. There was probably something wrong with that configuration. I didn't look into it further. Removing the collectfast package worked

Related

Django application running on top of Serverless + Lambda + API Gateway HTTP API is rewriting links to be prefixed with default

My Django Application (Largely REST Framework based) is currently producing URLs on the admin page that don't resolve. The expected result is that the Django Admin's login prompt submits the form with a POST to /admin/login. The resultant URL passed by as the form submission URL by Django is /$default/admin/login and that returns a 404 with the even more obtuse /$default/$default/admin/login/.
I'm presuming I have some sort of misconfiguration in either my Django configuration or serverless.yml.
As per the following serverless.yml I'm using API Gateway V2, Django through WSGI, and Lambda functions.
service: api
app: api
org: myapp
frameworkVersion: '3'
provider:
name: aws
runtime: python3.8
functions:
serve:
handler: wsgi_handler.handler
timeout: 20
environment:
DB_NAME: ${param:db_name}
DB_PASSWORD: ${param:db_password}
DB_USER: ${param:db_user}
DB_PORT: ${param:db_port}
DB_HOST: ${param:db_host}
events:
- httpApi: "*"
migration:
handler: migrate.handler
timeout: 60
environment:
DB_NAME: ${param:db_name}
DB_PASSWORD: ${param:db_password}
DB_USER: ${param:db_user}
DB_PORT: ${param:db_port}
DB_HOST: ${param:db_host}
custom:
wsgi:
app: myapp.wsgi.application
plugins:
- serverless-python-requirements
- serverless-wsgi
My URLs are pretty standard:
from django.contrib import admin
from django.urls import path, include
from rest_framework.schemas import get_schema_view
schema_view = get_schema_view(
title="MyApp",
description="MyApp Universal API",
version="1.0.0",
)
urlpatterns = [
path("admin/", admin.site.urls),
path("user/", include("myapp.core.urls"), name="user"),
path("openapi", schema_view, name="openapi-schema"),
]
My configuration is even more standard:
import os
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "not for you :)"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['*']
if 'CODESPACE_NAME' in os.environ:
codespace_name = os.getenv("CODESPACE_NAME")
codespace_domain = os.getenv("GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN")
CSRF_TRUSTED_ORIGINS = [f'https://{codespace_name}-8000.{codespace_domain}']
ROOT_URLCONF = "myapp.urls"
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
'rest_framework',
"myapp.core",
]
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",
]
X_FRAME_OPTIONS = "ALLOW-FROM preview.app.github.dev"
ROOT_URLCONF = "myapp.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "myapp" / "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",
],
},
},
]
WSGI_APPLICATION = "myapp.wsgi.application"
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# Database
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME', 'neondb'),
'USER': os.environ.get('DB_USER', 'postgres'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST', 'localhost'),
'PORT': os.environ.get('DB_PORT', 5432),
}
}
# Password validation
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
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",
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATICFILES_DIRS = [
BASE_DIR / "myapp" / "static",
]
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3StaticStorage'
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = "myapp-django-static"
AUTH_USER_MODEL = 'core.User'
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
)
}
As for the resultant error message:
Any help (or ideas) would be greatly appreciated!
I've tried modifying the path structure of the serverless.yml and have been trawling through the Django source code for any hints to no avail. Naturally I'd just like Django admin to work. As far as the rest of the app, it works fine as the API itself isn't self referential. Django just isn't returning the correct path.
To put it in brief, Django thinks that all of my routes are prefixed by /$default/ they are not. I'm looking for either a solution to force the path to sent by Django to be / or a fix for my Serverless configuration to mitigate this issue.
I managed to resolve this with a rather niché Django settings option: FORCE_SCRIPT_NAME
While this doesn't explain why it is resolving the path to /$default/ it does mitigate this issue.
If you're using this for a different use case than mine and your path is in a subdirectory (e.g the opposite issue to mine) then you would add your path in FORCE_SCRIPT_NAME instead.
See the link I've provided for more information.
Add the following to your app's settings.py, or any file you're using as your DJANGO_SETTINGS_MODULE.
# Force Django to resolve the URL to the root of the site
# This is required for API Gateway <- WSGI -> Django path resolution to work properly.
FORCE_SCRIPT_NAME = ""

400 Bad Request Django/React

I have built a server with Django and I am receiving a 400 Bad Request within Postman when I check the POST method. However, it is displaying the JSON data within the Postman as well.
Originally, I thought it was a frontend issue, because my console log was stating
AxiosError {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
As I stated before, the error is showing in Postman so I'm assuming it's actually a server issue.
Im real "finicky" when it comes to file colors, and if it is any color than the default color, I feel like there is errors within the file. Could these orange/beige files contain the problem? If I click on one of those files Im met with:
The file is not displayed in the editor because it is either binary or uses an unsupported text encoding.
Because I am new to django, I don't want to do something that's going to create an even bigger problem than what I already have.
Below will be my settings.py
"""
Django settings for django_rest_api project.
Generated by 'django-admin startproject' using Django 4.1.4.
For more information on this file, see
https://docs.djangoproject.com/en/4.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.1/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-2r=5^!2(nj*^*m*sa_39h(xldjpau&$wmn&pc5=^frws#w&25="
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"corsheaders",
"rest_framework",
"todo_api",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
"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",
]
CORS_ALLOW_ALL_ORIGINS = True
ROOT_URLCONF = "django_rest_api.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"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",
],
},
},
]
WSGI_APPLICATION = "django_rest_api.wsgi.application"
# Database
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "todo_api",
"USER": "",
"PASSWORD" : '',
"HOST": "localhost"
}
}
# Password validation
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
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",
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
Below is my views.py
from django.shortcuts import render
from rest_framework import generics
from .serializer import TodoSerializer
from .models import Todo
# Create your views here.
class TodoList(generics.ListCreateAPIView):
queryset = Todo.objects.all().order_by('id')
serializer_class = TodoSerializer
class TodoDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Todo.objects.all().order_by('id')
serializer_class = TodoSerializer
Im not exactly sure what information everyone needs to provide a proper solution for this, but hopefully I have provided more than enough.
I think it is worth noting that I am using postgreql and my database is working properly, and I can access Django admin and manually enter data from there as well.

Configuring Google Cloud App Engine w Django

I'm following this tutorial
to deploy Django with Google Cloud. At the timestamp (13:39) he goes into settings.py in the Django project in VS Code and swaps some placeholders out for his own Google Cloud credentials. My settings.py however looks very different. The only thing in block caps that looks as if it might be a placeholder is "GOOGLE_CLOUD_PROJECT" and "SETTINGS_NAME". This is the part of the installation I can't get past because at the next step when I try to execute
python manage.py makemigrations
I get sent here:
else:
raise Exception("No local .env or GOOGLE_CLOUD_PROJECT detected. No secrets found.")
Hoping someone can glance over my settings.py and identify what I'm missing why that if block is going to Exception.
One thing to note: The top imports environ and google.cloud are not resolved. idk if that's got anything to do with it. This is how the file came out the can. I don't want to mess with it in case tshtf :D
settings.py
import io
import os
import environ
from google.cloud import secretmanager
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# [START gaestd_py_django_secret_config]
env = environ.Env(DEBUG=(bool, False))
env_file = os.path.join(BASE_DIR, ".env")
if os.path.isfile(env_file):
# Use a local secret file, if provided
env.read_env(env_file)
# [START_EXCLUDE]
elif os.getenv("TRAMPOLINE_CI", None):
# Create local settings if running with CI, for unit testing
placeholder = (
f"SECRET_KEY=a\n"
f"DATABASE_URL=sqlite://{os.path.join(BASE_DIR, 'db.sqlite3')}"
)
env.read_env(io.StringIO(placeholder))
# [END_EXCLUDE]
elif os.environ.get("GOOGLE_CLOUD_PROJECT", None):
# Pull secrets from Secret Manager
project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")
client = secretmanager.SecretManagerServiceClient()
settings_name = os.environ.get("SETTINGS_NAME", "django_settings")
name = f"projects/{project_id}/secrets/{settings_name}/versions/latest"
payload = client.access_secret_version(name=name).payload.data.decode("UTF-8")
env.read_env(io.StringIO(payload))
else:
raise Exception("No local .env or GOOGLE_CLOUD_PROJECT detected. No secrets found.")
# [END gaestd_py_django_secret_config]
SECRET_KEY = env("SECRET_KEY")
# SECURITY WARNING: don't run with debug turned on in production!
# Change this to "False" when you are ready for production
DEBUG = True
# SECURITY WARNING: App Engine's security features ensure that it is safe to
# have ALLOWED_HOSTS = ['*'] when the app is deployed. If you deploy a Django
# app not on App Engine, make sure to set an appropriate host here.
ALLOWED_HOSTS = ["*"]
# Application definition
INSTALLED_APPS = [
"polls.apps.PollsConfig",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
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 = "mysite.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"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",
],
},
},
]
WSGI_APPLICATION = "mysite.wsgi.application"
# Database
# [START db_setup]
# [START gaestd_py_django_database_config]
# Use django-environ to parse the connection string
DATABASES = {"default": env.db()}
# If the flag as been set, configure to use proxy
if os.getenv("USE_CLOUD_SQL_AUTH_PROXY", None):
DATABASES["default"]["HOST"] = "127.0.0.1"
DATABASES["default"]["PORT"] = 5432
# [END gaestd_py_django_database_config]
# [END db_setup]
# Use a in-memory sqlite3 database when testing in CI systems
# TODO(glasnt) CHECK IF THIS IS REQUIRED because we're setting a val above
if os.getenv("TRAMPOLINE_CI", None):
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
}
}
# Password validation
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", # noqa: 501
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", # noqa: 501
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", # noqa: 501
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", # noqa: 501
},
]
# Internationalization
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
STATIC_ROOT = "static"
STATIC_URL = "/static/"
STATICFILES_DIRS = []
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
Django wants you to provide a SECRET_KEY. There are a couple of ways to provide such key, but one way is to create an .env file containing the SECRET_KEY in the same folder where the manage.py file is located.
A SECRET_KEY can be generated using the following code snippet (run it wherever you find convenient, but don't add the resulting key string to your settings.py file):
from django.core.management.utils import get_random_secret_key
get_random_secret_key()
Take the resulting output (it's a 50 character long string) and add it to the .env file with the following format:
SECRET_KEY="the-50-character-string-here"
You might potentially also have to replace BASE_DIR in the settings.py file with the following in order to properly load the .env file (note how the first row is out-commented).
#BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
BASE_DIR = os.getcwd()
You might run into more problems further down the road related to your database setup. Check out this and this SO question.
You can also consider checking out the Guide which is what the tutorial you're referring to is following.

Error while using ckeditor with Django version 2.x

Please be informed I researched Stack Overflow and ckeditor documentation and configured accordingly.
First I install ckeditor using
pip install django-ckeditor
Then I configured my settings.py as below
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
# media
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
# Static files (CSS, JavaScript, Images)
STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]
CKEDITOR_BASEPATH = "/static/ckeditor/ckeditor"
# CKEditor settings
CKEDITOR_UPLOAD_PATH = "uploads/"
CKEDITOR_JQUERY_URL = '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'
# This ensures you have all toolbar icons
CKEDITOR_CONFIGS = {
'default': {
'toolbar': None,
},
}
Then I configured my urls.py (project's url) as below
url(r'^ckeditor/', include('ckeditor_uploader.urls'))
Then I ran command collect static
ckeditor statics are collected in right location defined in settings which is /static/ckeditor/ckeditor
After that I imported and used ckeditor richtextfield in my model
from django.db import models
from ckeditor.fields import RichTextField
class Post(models.Model):
post = models.RichTextField()
While makemigrations i am getting the following error
AttributeError: module 'django.db.models' has no attribute 'RichTextField'
Change from:
post = models.RichTextField()
to:
post = RichTextField()
And in CKEDITOR_BASEPATH add "/" to the end.
CKEDITOR_BASEPATH = "/static/ckeditor/ckeditor/"

All static assets coming back as "404 (Not found)" in Django/React app

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.
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.