I am getting a funny 500 error when I switch to Debug=False in my Heroku app when I deploy. I have set Debug=True when I deploy just to try it out and it works perfectly - so the issue is only when Debug is set to False.
I'm not sure where to start here. Some searching has led me to believe it's whitenoise causing the issue but it's not clear. The command:
Output from heroku logs --source app
2018-09-13T12:29:53.137785+00:00 app[web.1]: 10.45.76.149 - - [13/Sep/2018:12:29:53 +0000] "GET / HTTP/1.1" 500 27 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
2018-09-13T12:29:53.279702+00:00 app[web.1]: 10.81.224.221 - - [13/Sep/2018:12:29:53 +0000] "GET /favicon.ico HTTP/1.1" 404 85 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
2018-09-13T12:29:53.792280+00:00 app[web.1]: 10.45.76.149 - - [13/Sep/2018:12:29:53 +0000] "GET /favicon.ico HTTP/1.1" 404 85 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
I have tried fixing as per this solution but to no avail;
See below for my settings:
import os
import posixpath
from os import environ
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'A SECRET'
DEBUG = True
ALLOWED_HOSTS = ['*']
SITE_TITLE = "Penguiness"
SITE_TAGLINE = "Amazing records for amazing species"
# Application definition
INSTALLED_APPS = [
'app',
# Add your apps here to enable them
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'compressor',
'gunicorn'
]
MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
]
ROOT_URLCONF = 'Penguinness.urls'
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
# STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
STATIC_URL = '/static/'
STATIC_ROOT = posixpath.join(*(BASE_DIR.split(os.path.sep) + ['app/static']))
PROJECT_APP_PATH = os.path.dirname(os.path.abspath(__file__))
PROJECT_APP = os.path.basename(PROJECT_APP_PATH)
PROJECT_ROOT = BASE_DIR = os.path.dirname(PROJECT_APP_PATH)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(PROJECT_ROOT, "app/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',
'app.context_processors.global_settings',
],
},
},
]
WSGI_APPLICATION = 'Penguinness.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
# DATABASES = {
# 'default': {
# DATABASE STUFF
# }
# }
SECURE_PROXY_SSL_HEADER = (
"HTTP_X_FORWARDED_PROTO",
"https"
)
# Password validation
# https://docs.djangoproject.com/en/1.9/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/1.9/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
EMAIL_USE_TLS = True
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_PASSWORD = PASSWORD #my gmail password
EMAIL_HOST_USER = EMAIL #my gmail username
EMAIL_PORT = 587
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
import dj_database_url
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': ('%(asctime)s [%(process)d] [%(levelname)s] ' +
'pathname=%(pathname)s lineno=%(lineno)s ' +
'funcname=%(funcName)s %(message)s'),
'datefmt': '%Y-%m-%d %H:%M:%S'
},
'simple': {
'format': '%(levelname)s %(message)s'
}
},
'handlers': {
'null': {
'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose'
}
},
'loggers': {
'testlogger': {
'handlers': ['console'],
'level': 'INFO',
}
}
}
Okay - having battled for a bit I've found a solution to both issues I was having.
Issue 1: Unable to view heroku logs --source app:
I had to first add LOGGING to the settings.py file:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': ('%(asctime)s [%(process)d] [%(levelname)s] ' +
'pathname=%(pathname)s lineno=%(lineno)s ' +
'funcname=%(funcName)s %(message)s'),
'datefmt': '%Y-%m-%d %H:%M:%S'
},
'simple': {
'format': '%(levelname)s %(message)s'
}
},
'handlers': {
'null': {
'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose'
}
},
'loggers': {
'testlogger': {
'handlers': ['console'],
'level': 'INFO',
}
}
}
More importantly was to get the relevant errors to propagate up through the Heroku logs. To do this, in settings.py I wrote the line:
DEBUG_PROPAGATE_EXCEPTIONS = True
This gave me an error associated with my static files. More specifically, it was giving me this error:
ValueError: Missing staticfiles manifest entry for 'images/favicon.png'
Issue 2: the 500 error
After determining that there was an error processing static images, I searched and someone suggested running:
python manage.py collectstatic
I did this, but was still finding the error. The next thing was to ensure that Whitenoise was commented out:
#STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
However, this was resulting in the error:
2018-09-13T13:13:49.905187+00:00 app[web.1]: "When using Django Compressor together with staticfiles, "
2018-09-13T13:13:49.905190+00:00 app[web.1]: ImproperlyConfigured: When using Django Compressor together with staticfiles, please add 'compressor.finders.CompressorFinder' to the STATICFILES_FINDERS setting.
I tried to add compressor.finders.CompressorFinder but that gave me a similar error to above. So I ignored that. After some searching I found that I had to basically disable compressor (at least as I understand it) by adding this to settings.py:
COMPRESS_ENABLED = os.environ.get('COMPRESS_ENABLED', False)
This didn't completely fix the problem as then I was having issues locating the static files. So, I had to set my STATIC_ROOT to this:
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
Pushed to heroku and there you have it... Debug=False now working
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
helped in my case
For me the issue was that I had commented HTML code block
<!--
Some reference to images.
-->
Collectstatic ignores images that are referenced within comment but there is a typical behaviour in Django processing when Debug=False is set which actually tries to parse and verify images within HTML comments (This does not happen when Debug=True is set).
When I removed comments, I was able to render the page and 500 error was gone.
I was using white noise in my applications after removing this:
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
and adding this:
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
solved the problem
The reason may be very silly it may be something like static files path names you provided in your templates.
Let's see a example:
CODE-1
<img src="{% static '/images/Rectangle 2.png' %}" class="card-img-top" alt="..." >
CODE-2
<img src="{% static 'images/Rectangle 2.png' %}" class="card-img-top" alt="..." >
Both code1 and code2 will work properly when DEBUG=True.
But if DEBUG=False code2 will work fine but code1 won't work. The extra slash(/) before images creates an issue, i.e., production can't configure the path properly.
So please have a look at your static file paths in your templates. That might be the issue.
Set DEBUG=False in .env file in django project, configure the DEBUG variable in settings to point to the variable in .env file. Add DEBUG = False to configs in Heroku. I don't know why this works but I'm glad it does.
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
Related
I was having issues with print statements and Django and I saw on here that its better to do logging. I am not sure what I am doing wrong though. It logs sometimes to console and other times it doesn't for the same page and I cant get it to log anything in my post method.
I have tried doing the logger = logging.getLogger("mylogger") above all the class views, ive tried adding that line to each individual method and ive tried only having it in 1 at a time. Any thoughts?
Settings.py
"""
Django settings for caspers_trading_tools project.
Generated by 'django-admin startproject' using Django 4.0.1.
For more information on this file, see
https://docs.djangoproject.com/en/4.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.0/ref/settings/
"""
from pathlib import Path
import os
# 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.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-d^#mw27((%t$wzj+3eykdmfmweufzep44sgkhib)^n1thdh!y6'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'landing_page',
'trading_log',
'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 = 'caspers_trading_tools.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
BASE_DIR / "templates",
BASE_DIR / "templates" / "includes"
],
'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 = 'caspers_trading_tools.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/4.0/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.0/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.0/howto/static-files/
STATIC_URL = 'static/'
STATICFILES_DIRS = [
BASE_DIR / "static"
]
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'filters': ['require_debug_true'],
},
},
'loggers': {
'mylogger': {
'handlers': ['console'],
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
'propagate': True,
},
},
}
Views.py
class CreateOrderView(View):
def get(self, request,):
logger = logging.getLogger("mylogger")
logger.info("TEST")
# this should be removed once user_ids are implemented through login system and session creation
request.session["user_id"] = 1
# should be set to session.get("user_id") probably in the future
user_id = request.session.get("user_id")
trade_form = CreateTradeForm()
order_form = CreateOrderForm()
context = {}
context["user_id"] = user_id
context["order_form"] = order_form
context["trade_form"] = trade_form
return render(request, "trading_log/add-order.html", context)
def post(self, request):
trade_form = CreateTradeView(request.POST)
order_form = CreateOrderForm(request.POST)
trade = trade_form.save(commit=False)
order = order_form.save(commit=False)
logger = logging.getLogger("mylogger")
logger.info("TEST")
# logger.info("TRADE", trade)
# logger.info("ORDER", order)
return HttpResponseRedirect(reverse("add-order-page"))
If you need any other files please let me know. I dont think ive done anything anywhere to make logging work.
I see that you're using the RequireDebugTrue filter, which means that you will only get logs printed if DEBUG is set to True in your settings file (which you do not show in your post).
Additionally, you do not need to set the logger variable in every single method. It's ok to declare it once per module globally.
I'm trying to schedule a task in celery.
celery.py inside the main project directory
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
from celery.schedules import crontab
os.environ.setdefault('DJANGO_SETTINGS_MODULE','example_api.settings')
app = Celery('example_api')
app.config_from_object('django.conf:settings',namespace="CELERY")
app.conf.beat_schedule = {
'add_trades_to_database_periodically': {
'task': 'transactions.tasks.add_trades_to_database',
'schedule': crontab(minute='*/1'),
# 'args': (16,16),
},
}
app.autodiscover_tasks()
The project has a single app called transactions.
function inside transactions/tasks.py
#task(name="add_trades_to_database")
def add_trades_to_database():
start_date = '20000101' #YYYYDDMM
end_date = '20150101'
url = f'https://api.example.com/trade-retriever-api/v1/fx/trades?fromDate={start_date}&toDate={end_date}'
content = get_json(url)
print(content)
save_data_to_model(content,BulkTrade)
settings.py
"""
Django settings for nordea_api project.
Generated by 'django-admin startproject' using Django 3.2.7.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
from pathlib import Path
import os
import environ
env = environ.Env()
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
env.read_env(env.str('BASE_DIR', '.env'))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'example'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'rest_framework',
'rest_framework.authtoken',
'rest_auth',
'rest_auth.registration',
'allauth',
'allauth.account',
'allauth.socialaccount',
'corsheaders',
'transactions.apps.TransactionsConfig',
'django_celery_beat',
]
# REST_FRAMEWORK = {
# 'DEFAULT_PERMISSION_CLASSES':[
# 'rest_framework.permissions.IsAuthenticated',
# ]
# }
CELERY_TIMEZONE = "UTC"
# CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
DEFAULT_AUTHENTICATION_CLASSES = [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
]
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = os.environ.get('EMAIL')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_PASSWORD')
DEFAULT_FROM_EMAIL = os.environ.get('EMAIL')
SITE_ID = 1
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'example_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 = 'example_api.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'example_transaction',
'USER': 'myUser',
'PASSWORD': os.environ.get('DATABASE_PASSWORD'),
'HOST':'localhost',
'PORT':'',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/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/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
I'm using rabbitmq-server for taskqueues.
My rabbitmq-server is active all the time.
Other celery task work absolutely fine.(I've tried implementing an email function which works well using celery).
I start celery worker and beat using
celery -A project worker -l info
celery -A project beat -l info
Following error appears in the worker terminal
The full contents of the message body was:
'[[], {}, {"callbacks": null, "errbacks": null, "chain": null, "chord": null}]' (77b)
Traceback (most recent call last):
File "/home/......./env/lib/python3.8/site-packages/celery/worker/consumer/consumer.py", line 581, in on_task_received
strategy = strategies[type_]
KeyError: 'transactions.tasks.add_trades_to_database'
I'm using ubuntu.
You have explicitly named the task "add_trades_to_database"
#task(name="add_trades_to_database")
def add_trades_to_database():
...
Yet, you are scheduling the task under the name "transactions.tasks.add_trades_to_database"
app.conf.beat_schedule = {
'add_trades_to_database_periodically': {
'task': 'transactions.tasks.add_trades_to_database',
'schedule': crontab(minute='*/1'),
},
}
Solutions you can choose from:
Don't explicitly set a name for the task. Celery would set a default name for it based on the module names and the function name as documented. The beat schedule remains the same (assuming add_trades_to_database is located in my_proj/transactions/tasks.py::add_trades_to_database)
#task
def add_trades_to_database():
...
Or you can just change the beat schedule to refer to the explicitly set name.
app.conf.beat_schedule = {
'add_trades_to_database_periodically': {
'task': 'add_trades_to_database',
'schedule': crontab(minute='*/1'),
},
}
To emphasize, choose only one out of these 2 solutions, because doing both would obviously still fail for the same reason.
Also, note that when using Django, the convention is to use the decorator #shared_task so you might want to change your tasks to:
from celery import shared_task
#shared_task
def add_trades_to_database():
...
Here is my settings.py:
import os
import django_heroku
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = 'secret_key'
DEBUG = False
ALLOWED_HOSTS = ['*']
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'corsheaders',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
'rest_framework',
'django_celery_beat'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware', # CORS support [keep load position]
'django.middleware.common.CommonMiddleware',
#'django.middleware.cache.UpdateCacheMiddleware',
#'django.middleware.common.CommonMiddleware',
#'django.middleware.cache.FetchFromCacheMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'corsheaders.middleware.CorsPostCsrfMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CORS_ORIGIN_WHITELIST = [
"http://localhost:8080",
"http://127.0.0.1:8080",
"http://localhost:80"
]
CSRF_TRUSTED_ORIGINS = [
'http://localhost:8080',
]
ROOT_URLCONF = 'django_backend.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_backend.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'name',
'USER': 'user',
'PASSWORD': "pw",
'HOST': 'localhost',
'PORT': '5432'
}
}
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',
},
]
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
CELERY_BROKER_URL = 'redis://url:port'
CELERY_RESULT_BACKEND = 'redis://url:port'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = TIME_ZONE
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
},
'console':{
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
DEBUG_PROPAGATE_EXCEPTIONS = True
STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
django_heroku.settings(locals())
On my local server, I do not receive any errors. However in production, I get asset errors on any page that loads a static asset. For example trying to access the Django admin panel:
ValueError: Missing staticfiles manifest
entry for 'admin/css/base.css'
I have tried running python manage.py collectstatic which does not result in an error. It says 152 files collected in /staticfiles (confirmed they exist). Why is Django not able to find these static files? Another SO thread said to try setting ALLOWED_HOSTS to *, which I have as well. Other solutions such as trying the default static files settings configuration don't seem to work either.
Django does not serve static files when the server is running in production (so with DEBUG = False).
As is specified in the documentation on Configuring static files:
In addition to these configuration steps, you’ll also need to
actually serve the static files.
During development, if you use django.contrib.staticfiles, this will be done automatically by runserver when DEBUG is set to
True (see django.contrib.staticfiles.views.serve()).
This method is grossly inefficient and probably insecure, so it is
unsuitable for production.
See Deploying static files for proper strategies to serve static files
in production environments.
If you thus want to run your server in production, you will need to set up the nginx/apache/... configuration to serve static files. collectstatic is used to collect the static files over the static directories, such that you can easily configure your server.
The documentation on serving static files in production has a section on how to configure an Apache server to serve static files. In most cases, one does not run Django and serves static files on the same server. Usually there are two servers that each handle one of the cases, or one uses a CDN or S3 storage.
As an alterantive, you can use the whitenoise package, it manages to improve certain aspects Django's static files will not, although it still might not be the best option to serve the static files through the same server as the Django server:
Isn’t serving static files from Python horribly inefficient?
The short answer to this is that if you care about performance and
efficiency then you should be using WhiteNoise behind a CDN like
CloudFront. If you’re doing that then, because of the caching headers
WhiteNoise sends, the vast majority of static requests will be served
directly by the CDN without touching your application, so it really
doesn’t make much difference how efficient WhiteNoise is.
That said, WhiteNoise is pretty efficient. Because it only has to
serve a fixed set of files it does all the work of finding files and
determining the correct headers upfront on initialization. Requests
can then be served with little more than a dictionary lookup to find
the appropriate response. Also, when used with gunicorn (and most
other WSGI servers) the actual business of pushing the file down the
network interface is handled by the kernel’s very efficient sendfile
syscall, not by Python.
EDIT: MORE INFORMATION:
I added logging as suggested in the first answer, and got this:
ValueError: The file 'file/name' could not be found with <whitenoise.storage.CompressedManifestStaticFilesStorage object
ORIGINAL POST:
I'm running my Django site on locally, and when DEBUG=True it works fine. However, when I set DEBUG=False, it returns a 500 Server Error.
ALLOWED_HOSTS has been set to ['*'], and it still returns a 500 Server Error.
Here's my settings.py:
import os
import dj_database_url
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "**************************"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
# Application definition
INSTALLED_APPS = [
'my_app.apps.MyAppConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
# Disable Django's own staticfiles handling in favour of WhiteNoise, for
# greater consistency between gunicorn and `./manage.py runserver`. See:
# http://whitenoise.evans.io/en/stable/django.html#using-whitenoise-in-development
'whitenoise.runserver_nostatic',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'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',
],
'debug': DEBUG,
},
},
]
WSGI_APPLICATION = 'mysite.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'my_db',
'USER': 'admin',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '',
}
}
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/1.10/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'America/Los_Angeles'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Update database configuration with $DATABASE_URL.
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Allow all host headers
ALLOWED_HOSTS = ['*']
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles')
STATIC_URL = '/static/'
# Extra places for collectstatic to find static files.
STATICFILES_DIRS = [
os.path.join(PROJECT_ROOT, 'static'),
]
# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
The right way to approach this is to enable logging and Django itself will (usually) indicate the problem. The advantage of this approach is that it will be useful for future problems as well. Here's a sample logging setup that will log with DEBUG=false (borrowed from this answer):
# settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
'datefmt' : "%d/%b/%Y %H:%M:%S"
},
'simple': {
'format': '%(levelname)s %(message)s'
},
},
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': 'mysite.log',
'formatter': 'verbose'
},
},
'loggers': {
'django': {
'handlers':['file'],
'propagate': True,
'level':'DEBUG',
},
'MYAPP': {
'handlers': ['file'],
'level': 'DEBUG',
},
}
}
I have a website based on Django framework. I am running website via Nginx webserver (uWSGI,Django,Nginx). I want to stream mp3 files on my website with Accept-Ranges header. I want to serve my mp3 files with Nginx. I need my API to look like this
http://192.168.1.105/stream/rihanna
This must return mp3 file with partial download (Accept-Ranges).
My mp3 files are stored in : /home/docker/code/app/media/data/
When I run the server with these configurations and browse to 192.168.1.105/stream/rihanna , Django returns 404.
My Nginx conf:
# mysite_nginx.conf
# the upstream component nginx needs to connect to
upstream django {
server unix:/home/docker/code/app.sock; # for a file socket
# server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}
# configuration of the server
server {
# the port your site will be served on, default_server indicates that this server block
# is the block to use if no blocks match the server_name
listen 80 default;
include /etc/nginx/mime.types;
# the domain name it will serve for
server_name .example.com; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
location /media {
autoindex on;
sendfile on;
sendfile_max_chunk 1024m;
internal;
#add_header X-Static hit;
alias /home/docker/code/app/media/; # your Django project's media files - amend as required
}
location /static {
alias /home/docker/code/app/static/; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /home/docker/code/uwsgi_params; # the uwsgi_params file you installed
}
}
My views.py :
def stream(request, offset):
try:
mp3_path = os.getcwd() + '/media/data/' + offset + '.mp3'
mp3_data = open(mp3_path, "r").read()
except:
raise Http404()
response = HttpResponse(mp3_data, content_type="audio/mpeg", status=206)
response['X-Accel-Redirect'] = mp3_path
response['X-Accel-Buffering'] = 'no'
response['Content-Length'] = os.path.getsize(mp3_path)
response['Content-Dispostion'] = "attachment; filename=" + mp3_path
response['Accept-Ranges'] = 'bytes'
I want Nginx serve this files. And I really need Accept-Ranges enabled.
My Settings.py :
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
DEBUG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '192.168.1.105', '0.0.0.0']
# Application definition
INSTALLED_APPS = [
'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 = 'beats.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',
],
},
},
]
WSGI_APPLICATION = 'beats.wsgi.application'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
MEDIA_URL = os.path.join(BASE_DIR, 'media/')
# Database
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',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
STATIC_URL = '/static/'
My problem is: It doesn't work, and Django return 404 Error webpage.
First of all, I did not copy the Nginx configuration file to the available-sites path. And because of it, It didn't work.
And in my views.py:
response = HttpResponse(mp3_data, content_type="audio/mpeg", status=206)
response['X-Accel-Redirect'] = mp3_path
these 2 lines must be changed to:
response= HttpResponse('', content_type="audio/mpeg", status=206)
response['X-Accel-Redirect'] = '/media/data/' + file_name + '.mp3'