when I tried to run the project, static files are missing, and the settings.debug is set to False.
Django does not serve static files in production (when DEBUG = False) because doing so would be in their own words (As stated in the section Serving static files during development of the documentation):
This method is grossly inefficient and probably insecure, so
it is unsuitable for production.
Why is this inefficient one might say? Well static files are mostly larger in size than your normal HTML files, plus a website is bound to have lots of static files. If Django served static content even in production much of the time of the server would be wasted in serving these static files. Plus to serve multiple requests at the same time we run multiple Django processes simultaneously, if there are many requests for static files this will cause the processes to waste time serving them, causing other requests to wait if there are no free processes.
Plus as #Reda Bourial mentions in their comment Django doesn't handle compression well (One would want to compress their static files so that less bandwidth is required, both by the server and the client). Furthermore Django should focus more on the task it is designed for, which is rendering the pages requested by users (A CPU bound task), whereas serving static files is mostly just an Input / Output (I/O) task and for Django to spend time on these tasks (even when it is not efficient at them) is clearly a waste.
Servers like NGINX or Apache can serve static files much more efficiently, hence it is best to use them in production instead of having Django do it. For details on how to configure static files for production see Deploying static files [Django docs]
Actually in Django, while you run your project on the development server it won't serve your static files when you try to serve the static files after changing DEBUG settings to False. It will work properly on the production or stagging server but not on localhost server.
Still, there is a way to do this you can get by running your development server on insecure mode.
Try this,
python manage.py runserver --insecure
it is not recommended, but if you are just getting started and want to understand more about what's going on, then you can also link directly:
urls.py:
from django.conf.urls.static import static
from django.contrib import admin
from djangoapp import settings
from webtools.views import *
from django.urls import path, include
"""
direct link on the server in production
"""
from django.views.static import serve as mediaserve
from django.conf.urls import url
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('webtools.urls')),
]
if settings.DEBUG:
import debug_toolbar
urlpatterns = [
path('__debug__/', include(debug_toolbar.urls)),
] + urlpatterns
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
else:
# direct link on server in production
urlpatterns += [
url(f'^{settings.MEDIA_URL.lstrip("/")}(?P<path>.*)$', mediaserve, {'document_root': settings.MEDIA_ROOT}),
url(f'^{settings.STATIC_URL.lstrip("/")}(?P<path>.*)$', mediaserve, {'document_root': settings.STATIC_ROOT}),
]
settings.py:
DEBUG = False
.
.
.
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = []
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
I have a Django project which sends automated e-mails with attached pdfs to users. At the moment I just have a normal /media/ folder with the pdf in it which the code points to. This works in development but throws a server error in production.
My question is how do I server media files in production? I have read a lot about it but can't find exactly what I'm after.
I use collectstatic in my production environment which works for static files, I'd expect something similar for media files.
urls
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('page.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
settings
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static_files')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "static_media")
views.py (that sends the file)
file_path = os.path.join(settings.STATIC_ROOT+'\\pdf\\free_pdf.pdf')
...
msg.attach_file(file_path)
passenger.wsgi
import os
import sys
sys.path.append(os.getcwd())
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
import django.core.handlers.wsgi
from django.core.wsgi import get_wsgi_application
from whitenoise import WhiteNoise
SCRIPT_NAME = os.getcwd()
SCRIPT_NAME = '' #solution for damn link problem
class PassengerPathInfoFix(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
from urllib.parse import unquote
environ['SCRIPT_NAME'] = SCRIPT_NAME
request_uri = unquote(environ['REQUEST_URI'])
script_name = unquote(environ.get('SCRIPT_NAME', ''))
offset = request_uri.startswith(script_name) and len(environ['SCRIPT_NAME']) or 0
environ['PATH_INFO'] = request_uri[offset:].split('?', 1)[0]
return self.app(environ, start_response)
application = get_wsgi_application()
application = PassengerPathInfoFix(application)
application = WhiteNoise(application, root='/home/mysite/mysite/static_files')
(this code is from when I abandoned the media folder and was trying to just serve it with my static files)
My proj structure:
|project
|__app
|__static
| |__app
| |__style.css
|__media
| |__app
| |__pdfToBeSent
|__static_files (generated by collectstatic)
|__media_files (i created this)
collectstatic also doesn't copy my projects media files into media_files, I have been copying them in there myself (unsure about this).
I have also tried moving the media file to every possible location in my project
I am also serving my static files with whitenoise.
Thank you.
Since I was in a similar situation (on the same hosting, A2Hosting), I will try to share my understanding of the problem and the solution I opted for.
Pardon me if I may seem presumptuous in this presentation, I'm simply trying to retrace all the points that represent the flow of thoughts that led me to this solution.
A small premise: if with "media files" you intend multimedial files, such as images and so on, I think you shouldn't use the Django media folder as it's designed to serve files uploaded by the users.
Not knowing if your PDFs are indeed uploaded by some user or not, I'll try to expose my solution anyway.
When in a production environment, Django isn't going to serve static and media files.
For the former I too used WhiteNoise, while for the latter the approach is different (at least on a shared hosting base).
When we set Debug = False in settings.py I suspect that the media folder, created along with the Django project, becomes somewhat unreadable/unaccessible (I cannot tell if by the hand of Django or by the hand of the hosting, or a conjuction of the two).
The official method to handle media files is indeed to rely on an external storage service (like Amazon S3), but this solution isn't suitable for budget limited scenarios.
In my situation, I had the Django app running on a subdomain related to my main domain.
Principal domain: www.mydomain.com
App domain: subdomain.mydomain.com
Leaving the media folder created with the Django project where it was, I created another one in the following unix path:
/home/A2hosting_username/subdomain.mydomain.com/media
Then, in settings.py I changed the MEDIA_ROOT variable from:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
to:
MEDIA_ROOT = '/home/A2hosting_username/subdomain.mydomain.com/media'
After that, in the model.py class used to define the database and interact with it, I specified the path to the uploaded media (videos, in my case) in this way:
class Video(models.Model):
name = models.CharField(max_length=50)
path = models.FileField(upload_to="../media/videos", null=True, verbose_name="")
Since we don't have access to the Apache config file, it may be useful to edit the .htaccess file (relative to subdomain.mydomain.com) in the following way, to prevent the browser to "time out" when the uploaded file is somewhat heavy:
<ifModule mod_headers.c>
Header set Connection keep-alive
</ifModule>
I hope this can be of any help.
Am building an app using Django as my workhorse. All has been well so far - specified db settings, configured static directories, urls, views etc. But trouble started sneaking in the moment I wanted to render my own beautiful and custom 404.html and 500.html pages.
I read the docs on custom error handling, and set necessary configurations in UrlsConf, created corresponding views and added the 404.html and the 500.html to my app's template directory (specified in the settings.py too).
But the docs say you can actually view custom error views until Debug is Off, so I did turn it off to test my stuff, and that's when stuff goes berserk!
Not only do I fail to view the custom 404.html (actually, it loads, but because my error pages each contain a graphic error message -as some nice image), the source of the error page loads, but nothing else loads! Not even linked CSS or Javascript!
Generally, once I set DEBUG = False, all views will load, but any linked content (CSS, Javascript, Images, etc) wont load! What's happening? Is there something am missing, concerning static files and the DEBUG setting?
If you still need to server static locally (e.g. for testing without debug) you can run devserver in insecure mode:
manage.py runserver --insecure
With debug turned off Django won't handle static files for you any more - your production web server (Apache or something) should take care of that.
In urls.py I added this line:
from django.views.static import serve
add those two urls in urlpatterns:
url(r'^media/(?P<path>.*)$', serve,{'document_root': settings.MEDIA_ROOT}),
url(r'^static/(?P<path>.*)$', serve,{'document_root': settings.STATIC_ROOT}),
and both static and media files were accesible when DEBUG=FALSE.
You can use WhiteNoise to serve static files in production.
Install:
pip install WhiteNoise==2.0.6
And change your wsgi.py file to this:
from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise
application = get_wsgi_application()
application = DjangoWhiteNoise(application)
And you're good to go!
Credit to Handlebar Creative Blog.
BUT, it's really not recommended serving static files this way in production. Your production web server(like nginx) should take care of that.
Johnny's answer is great, but still didn't work for me just by adding those lines described there. Based on that answer, the steps that actually worked for me where:
Install WhiteNoise as described:
pip install WhiteNoise
Create the STATIC_ROOT variable and add WhiteNoise to your MIDDLEWARE variable in settings.py:
#settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', #add whitenoise
'django.contrib.sessions.middleware.SessionMiddleware',
...
]
#...
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') ##specify static root
Then, modify your wsgi.py file as explained in Johnny's answer:
#wsgi.py
from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise
application = get_wsgi_application()
application = DjangoWhiteNoise(application)
After that, deploy your changes to your server (with git or whatever you use).
Finally, run the collectstatic option from your manage.py on your server. This will copy all files from your static folders into the STATIC_ROOT directory we specified before:
$ python manage.py collectstatic
You will now see a new folder named staticfiles that contains such elements.
After following these steps you can now run your server and will be able to see your static files while in Production mode.
Update: In case you had version < 4 the changelog indicates that it's no longer necessary to declare the WSGI_APPLICATION = 'projectName.wsgi.application' on your settings.py file.
If you are using the static serve view in development, you have to have DEBUG = True :
Warning
This will only work if DEBUG is True.
That's because this view is grossly
inefficient and probably insecure.
This is only intended for local
development, and should never be used
in production.
Docs: serving static files in developent
Updated link, and this
EDIT: You could add some urls just to test your 404 and 500 templates, just use the generic view direct_to_template in your urls.
from django.views.generic.simple import direct_to_template
urlpatterns = patterns('',
('^404testing/$', direct_to_template, {'template': '404.html'})
)
You actually can serve static files in a production Django app, securely and without DEBUG=True.
Rather than using Django itself, use dj_static in your WSGI file (github):
requirements.txt:
...
dj-static==0.0.6
YOURAPP/settings.py:
...
STATIC_ROOT = 'staticdir'
STATIC_URL = '/staticpath/'
YOURAPP/wsgi.py:
...
from django.core.wsgi import get_wsgi_application
from dj_static import Cling
application = Cling(get_wsgi_application())
You can debug this in many different ways. Here's my approach.
localsettings.py:
DEBUG = False
DEBUG404 = True
urls.py:
from django.conf import settings
import os
if settings.DEBUG404:
urlpatterns += patterns('',
(r'^static/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': os.path.join(os.path.dirname(__file__), 'static')} ),
)
Be sure to read the docs ;)
https://docs.djangoproject.com/en/2.0/howto/static-files/#limiting-use-to-debug-true
Ultimate solution:-
So basically when you make debug = False, Django doesn't want to take care of your static files.
So we want something that can take care of our files.
The answer is whitenoise.
pip install whitenoise in your environment
Add 'whitenoise.middleware.WhiteNoiseMiddleware' in your middleware list in settings.py.
This should be added just below the 'django.middleware.security.SecurityMiddleware' and above all the remaining middleware. So that your middleware list will look like this:-
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
# add it exactlyhere
'django.contrib.sessions.middleware.SessionMiddleware',
'...'
]
Add 'whitenoise.runserver_nostatic' on top of your installed apps
So that your installed apps list will look like this:-
INSTALLED_APPS = [
'whitenoise.runserver_nostatic',
'django.contrib.admin',
'django.contrib.auth',
'...'
]
Done, you will be able to serve static files in production now!!
From here I took help by mixing a few answers. Here, I am adding my whole parts. [I am doing this for a beginners help and for my future use as well]
Well at first the question is why Debug=False needed!
I put my project in AWS and it was being connection timeout after few hours because of memory leaking.
At first I thought for celery. [of course I am just a beginner]
Then I put DEBUG=False from DEBUG=True As we can see the security warning in settings.py
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
Once I did that my staticfiles were not loading successfully in webpages.
Then I searched everywhere and at first tried from here the --insecure command to runserver.
python manage.py runserver --insecure
Which is successful but I don't want the insecure mode in my project when it is in production.
And as the proper solution [according to me] I followed the steps below.
At first, I correct the static URL,root, and dir in settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
Then collect the static files by command
python manage.py collectstatic
Now the second step, [which also provided here]
At first install whitenoise in your project directory in the command line
pip install whitenoise
Then Add 'whitenoise.middleware.WhiteNoiseMiddleware' in your middleware list in settings.py.
This should be added just below the 'django.middleware.security.SecurityMiddleware' and above all the remaining middleware. So that your middleware list will look like this:-
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', #after this line
'whitenoise.middleware.WhiteNoiseMiddleware', #add it exactlyhere
'django.contrib.sessions.middleware.SessionMiddleware', #before this
'...'
]
Add 'whitenoise.runserver_nostatic' on top of your installed apps So that your installed apps list will look like this:-
INSTALLED_APPS = [
'whitenoise.runserver_nostatic',
'django.contrib.admin',
'django.contrib.auth',
'...'
]
Done, you will be able to serve static files in production now!! [I did on my local environment as well]
Just use the runserver command as always no insecure or anything needed.
python manage.py runserver
Boom!!! It's working for me.
Hahaha. I know kinda childish nature but I am so happy now.
Thanks to everyone who provided answers here and help my work.
This is Exactly you must type on terminal to run your project without DEBUG = TRUE
and then you see all assets (static) file is loading correctly On local server .
python manage.py runserver --insecure
--insecure : it means you can run server without security mode
For last versions of Django please look at the answer here: https://stackoverflow.com/a/7639983/6180987
For django version below 1.10 the solution should work:
Just open your project urls.py, then find this if statement.
if settings.DEBUG:
urlpatterns += patterns(
'django.views.static',
(r'^media/(?P<path>.*)','serve',{'document_root': settings.MEDIA_ROOT}), )
You can change settings.DEBUG on True and it will work always. But if your project is a something serious then you should to think about other solutions mentioned above.
if True:
urlpatterns += patterns(
'django.views.static',
(r'^media/(?P<path>.*)','serve',{'document_root': settings.MEDIA_ROOT}), )
In django 1.10 you can write so:
urlpatterns += [ url(r'^media/(?P<path>.*)$', serve, { 'document_root': settings.MEDIA_ROOT, }), url(r'^static/(?P<path>.*)$', serve, { 'document_root': settings.STATIC_ROOT }), ]
when i make DEBUG = True my static are doesn't work.
if i run my project in python manage.py runserver --insecure . By this i got my static as well.
Solution 1:
python manage.py runserver --insecure
Solution 2:
But I Need Permanent Solution. then i install pip install dj-static==0.0.6 and add some code to my wsgi.py file:
from django.core.wsgi import get_wsgi_application
from dj_static import Cling
application = Cling(get_wsgi_application())
and then i added some in setting.py:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, '/static/')
STATICFILES_DIRS = [
BASE_DIR / "static",
]
I agree with Marek Sapkota answer; But you can still use django URFConf to reallocate the url, if static file is requested.
Step 1: Define a STATIC_ROOT path in settings.py
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
Step 2: Then collect the static files
$ python manage.py collectstatic
Step 3: Now define your URLConf that if static is in the beginning of url, access files from the static folder staticfiles. NOTE: This is your project's urls.py file:
from django.urls import re_path
from django.views.static import serve
urlpattern += [
re_path(r'^static/(?:.*)$', serve, {'document_root': settings.STATIC_ROOT, })
]
I got this problem today and this fixed it while on development, If you still need to server static locally (e.g. for testing without debug) you can run devserver in insecure mode:
manage.py runserver --insecure
Don't worry because when in production, this hosting platform (Apache, Heroku E.T.C ) would handle serving the static files for you.
Note: Heroku Doesn't server static files, you'd want to put it on AWS or MS Azure
nginx,settings and url configs
If you're on linux this may help.
nginx file
your_machn:/#vim etc/nginx/sites-available/nginxfile
server {
server_name xyz.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /var/www/your_prj;
}
location /media/ {
root /var/www/your_prj;
}
...........
......
}
urls.py
.........
.....
urlpatterns = [
path('admin/', admin.site.urls),
path('test/', test_viewset.TestServer_View.as_view()),
path('api/private/', include(router_admin.urls)),
path('api/public/', include(router_public.urls)),
]
if settings.DEBUG:
import debug_toolbar
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
settings.py
.....
........
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
.....
....
Ensure to run:
(venv)yourPrj$ ./manage.py collectstatic
yourSys# systemctrl daemon-reload
This is normal and intended behavior.
Warning
This will only work if DEBUG is True.
you can actually view custom error views until Debug is Off
If Django is just reading from the filesystem and sending out a file, then it has no advantage over a normal web server, all web servers are capable to server the files on it's own.
Furthermore, if you serve static files with Django, you will keep the Python process busy for the duration of the request and it will be unable to serve the dynamic requests to which it is more suited.
For these reasons, the Django static view is designed only for use during development and will not work if your DEBUG setting is False.
Since during development we only usually have one person accessing the site at a time (the
developer), Django is fine to serve static files.
Support for string view arguments to url() is deprecated and will be removed in Django 1.10
My solution is just small correction to Conrado solution above.
from django.conf import settings
import os
from django.views.static import serve as staticserve
if settings.DEBUG404:
urlpatterns += patterns('',
(r'^static/(?P<path>.*)$', staticserve,
{'document_root': os.path.join(os.path.dirname(__file__), 'static')} ),
)
I did the following changes to my project/urls.py and it worked for me
Add this line :
from django.conf.urls import url
and add :
url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT, }),
in urlpatterns.
Although it's not safest, but you can change in the source code. navigate to Python/2.7/site-packages/django/conf/urls/static.py
Then edit like following:
if settings.DEBUG or (prefix and '://' in prefix):
So then if settings.debug==False it won't effect on the code, also after running try python manage.py runserver --runserver to run static files.
NOTE: Information should only be used for testing only
I have a Django app running on Heroku/Cedar, configured as per the instructions at https://devcenter.heroku.com/articles/django
Using gunicorn as per Heroku's instructions fails to include the static files required for Django's admin to function. I can change the Procfile to "manage.py run_gunicorn" for local development, but that doesn't fly on Heroku.
I've searched all over for a fix - is there some way to include the admin static files without throwing them on S3 with my other static files?
If you use runserver and configure your app with DEBUG=True, then it will serve the admin files just like on your development machine. However, this is definitely not the recommended way to do it, and I would suggest that you put them on S3.
Using the django-storages app it's very easy to configure collectstatic to automatically push all the admin files to S3. You can find directions here
Check out this post: http://matthewphiong.com/managing-django-static-files-on-heroku
If that doesn't work for you try adding the following to your urls.py after the normal url pattern tuple. Make sure you have your STATIC_ROOT set and you've run collect static on your local environment all before pushing to heroku.
urlpatterns += patterns('',
url(r'^static/(?P<path>.*)$', 'django.views.static.serve', {
'document_root': settings.STATIC_ROOT,
}),
)
just add these instead
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()
using django 1.4.1
It seems little late compared to the asked date. But I got into this issue and spent 30 mins on what I did wrong. So here it is the magic solution for those who might fall in this trap.
There is some problem with Heroku's django.contrib.staticfiles.urls
SOLUTION
You need to install dj-static (Link to download) on your Heroku setup.
It's a Django middleware utility that allows to properly serve static assets from production with a WSGI server like Gunicorn.
I hope this will help someone.
create 'static' folder into your 'project_directory'.
set the 'STATIC_ROOT' path in 'settings.py' file which can serve your admin-site's static files.
STATIC_ROOT = (os.path.join(os.path.dirname(__file__), '..', 'static'))
Add STATIC_ROOT in '/urls.py'
from django.conf import settings
urlpatterns += patterns('',
url(r'^static/(?P<path>.*)$', 'django.views.static.serve', {
'document_root': settings.STATIC_ROOT,
}),
)
Run the following command that will copy all the admin static files into project's static folder.
python manage.py collectstatic
Now do git add, commit and push heroku master.
If you are deploying to Heroku without using whitenoise (which I would suggest), definitely use dj_static https://pypi.python.org/pypi/dj-static!
I spent the past 3 hours trying to serve my files to heroku and dj_static worked within a matter of 2 minutes.
I got django admin working with following edits
urls.py(at the end)
import settings
urlpatterns += patterns('',
url(r'^static/(?P<path>.*)$', 'django.views.static.serve', {
'document_root': settings.STATIC_ROOT,
}),
)
Procfile
web: gunicorn hellodjango.wsgi -b 0.0.0.0:$PORT
'django.contrib.staticfiles.views.serve'
instead of
'django.views.static.serve'
Follow this to fix all static related issues with Django and heroku.
In your settings.py paste this at the end
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
)
TEMPLATE_DIRS = (
os.path.join(BASE_DIR,'templates'),
)
STATIC_URL = '/static/'
Your template for a particular app should be in app_name/templates/app_name/
When you render template this is how you will specify template name
in views.py
.....
return render(request,'app_name/template_name.html',context)
For static files place your files here:
project_folder/app_name/static/app_name/css
project_folder/app_name/static/app_name/js
project_folder/app_name/static/app_name/img
to access your static file use path app_name/css/style_name.css
If you follow this, all your static files will load up fine in heroku as well as in your local development machine.