How does Django serve media files? - django

I have set up a Django application that uses images. I think I have set up the media settings MEDIA_ROOT and MEDIA_URL correctly. However the images don't show up. Do you know what can be the problem?
Let consider this example:
The image files are under /home/www/media/app/photos and we are trying to request http://example.com/photos/123.jpg
Should I use these settings?
MEDIA\_ROOT = /home/www/media
MEDIA_URL = http://example.com/app
UPDATE: Forgot to mention that I'm using built-in development server.

FOR DEVELOPMENT ONLY
You can setup a static media server for use with their development server by doing this in your urls.py file. I have attached the code showing how I use it (along with the forced DEBUG conditionals.)
from django.conf import settings
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
(r'^$', 'views.index'),
# Accounts
(r'^accounts/login/$', 'views.user_login'),
(r'^accounts/logout/$', 'views.user_logout'),
# Contrib Modules
(r'^admin/(.*)', admin.site.root),
)
if settings.DEBUG :
urlpatterns += patterns('',
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
)
I place my MEDIA_ROOT in a subdirectory of html/media and link to it as such in settings.py
MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'html/media/').replace('\\','/')
After development is finished, the project gets deployed to the web server where static media files are then served by Apache using directives.

Serving static content from Django is discouraged from the developer themselves (if I'm not wrong, it only works when in debug mode). You should use a dedicated web server, instead.
If you really need to do that, anyway, read the documentation on how to serve static files.

This is the correct way of showing image files with ImageField. Imagine we have a user profile picture:
models.py:
UserProfile:
profilePic= models.ImageField( upload_to='PATH_TO_UPLOAD', blank=True, null=True)
settings.py:
MEDIA_ROOT = 'FULL_PATH_OF_MEDIA'
MEDIA_URL = 'URL_OF_MEDIA'
urls.py:
urlpatterns = [
.
.
.
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
PATH_TO_UPLOAD is the path which user upload data goes. This is sub-directory of FULL_PATH_OF_MEDIA, which means the uploaded file will have
FULL_PATH_OF_MEDIA/PATH_TO_UPLOAD
full path.Now this content can be accessed at this url:
SITE_NAME/URL_OF_MEDIA/PATH_TO_UPLOAD
I also recommend reading this on static_files vs media_files
doc

You can just add those lines to your urls.py
from django.urls import re_path
from django.views.static import serve
urlpatterns = [
...
re_path(r'^media/(?P<path>.*)$', serve,{'document_root': settings.MEDIA_ROOT}),
]

I suspect you are getting the Django 404 page. Try directly accessing one of your images and see if that's happening.
If so, your need to configure your web server to not send requests within your media hierarchy to Django but to instead serve them directly. Here is a snip from my Apache conf file. The first section tells Apache to send everything to Django. The second section has "SetHandler None" which says "handle stuff under /media in the normal way."
See http://docs.djangoproject.com/en/dev/howto/deployment/modpython/ for all the exciting details.
Partial httpd.conf file for PrinceOfPinot.com (AKA pop):
<Location "/">
SetHandler python-program
PythonAutoReload Off
PythonDebug Off
PythonPath "['/var/www/production/pop', '/usr/local/lib/python2.5/site-packages/django'] + sys.path"
SetEnv DJANGO_SETTINGS_MODULE settings
PythonHandler django.core.handlers.modpython
</Location>
<Location "/media">
SetHandler None
AddOutputFilterByType DEFLATE text/html text/css application/x-javascript
</Location>

I'm aware that the original question is with the dev server, but for anyone else who is looking for a production environment answer:
https://docs.djangoproject.com/en/1.8/howto/static-files/deployment/ provides a guide on how to have django serve files in a production environment. From the tone of the guide, it does seem to imply that it is best to have a separate web server to handle the files or use mod_wsgi with Apache

Related

How To Serve media Files In Production

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.

Django Displaying images uploaded by ImageField properly

I'm building my own porfolio using Django, and I just had a question regarding uploading images using the ImageField.
I uploaded an image through the admin page using ImageField, and after a long search session, finally got my page to display the image successfully.
urls.py
from django.contrib import admin
from django.urls import include, path
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('',include('pages.urls')), # main landing page
path('admin/', admin.site.urls),
path('project/',include("projects.urls"))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
projects.html
<img src="{{project.image.url}}">
However, the official django docs say that this is not a good way to deploy a django site. Why is that, and what is the best/proper way to display images?
The reason is also given in documentation:
This method is grossly inefficient and probably insecure, so it is unsuitable for production.
Proper way of deploying media files in production is to use a reverse proxy server like NGINX or Apache, or you can use a S3 compatible storage(like Amazon S3) to serve those media files as well. I can give you an example configuration in NGINX for serving media files:
location /media {
alias /path/to/media/direcoty; # Change to your own media directory here.
access_log off;
}

Uploading files POST urls raise 404 when deploy

I'm deploying a django app on a host with apache and cPanel. I think I did all the steps that django needs to deploy. Everything works fine except dome admin posts urls.
When I'm sending a form via post from the admin site, and one of its fields is a File that will be uploaded to a directory, the server responses me 404. Some info:
Python 3.5, Django 1.11.9
Error: 404 Not Found
When: sending any post form containing a Choose File field, even if the file isn't mandatory.
The forms without files in their fields work fine. In production everything works perfect.
I have a symlink in the public_html folder to my media and static folders.
This error only shows in the admin page. I can upload file from the site without any problem
This is my code:
urls.py
urlpatterns = i18n_patterns(
url(r'^admin/', admin.site.urls),
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^', include('myapp.urls')),
prefix_default_language=False)
settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
This is my first time hosting a website, so, sorry if I'm asking a dummy question, but I couldn't find any solution, even here. Also, sorry for my English. Thanks for the future answers
EDIT
My non-admin forms work perfect. The problem is in the admin page. I edited my old question with the changes in bold
It can be web server problem. Check your cPanel settings
May be something wrong with your wsgi file location
Check up some tutorial for more info.
In case you are serving media files using django's static file server, the urlpatterns variable in your project's base urls.py file should be assigned in a specific order so that the i18n_patterns(...) assignment places before the static(...) url.
you should do it like so:
urlpatterns = i18n_patterns(
url(r'^admin/', admin.site.urls),
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^', include('myapp.urls')),
prefix_default_language=False)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Django Admin - FORCE_SCRIPT_NAME is appended twice to URL when POSTing

I have deployed Django to a sub directory (I don't have full control over the server so can't change the way it's deployed).
I added to my settings:
FORCE_SCRIPT_NAME = '/hub06'
STATIC_URL = FORCE_SCRIPT_NAME + '/static/'
Now when I go to /admin/hub06, it's working properly, I can login and browse all admin pages. As soon as I do a POST request though (adding a new model), the URL gets corrupted.
For example, when editing /hub06/admin/myapp/car/1
When I submit the form, it redirects to /hub06/hub06/admin/myapp/car/
So it adds script name twice. This is only for POST requests in Django admin.
Is this a linux host? is it running apache, nginx? It all depends on how your web server is configured.
If you really must have a url prefix like /hub06/ then you will need to update any settings in settings.py that return a url such as LOGIN_URL, STATIC_URL, LOGIN_REDIRECT_URL etc to contain the prefix.
I don't think you need to use FORCE_SCRIPT_NAME. Comment that bit out in the settings.py and update urls.py to add the following for example:
from django.conf.urls import patterns, include, url
from django.contrib.auth.views import login
from django.contrib import admin
admin.autodiscover()
urlpatterns2 = patterns('',
url(r'^$', 'yourapp.views.home', name='Home'),
url(r'^admin/', include(admin.site.urls)),
)
urlpatterns = patterns('',
url(r'^hub06/', include(urlpatterns2)),
)
Let me know how you go.
This was the solution:
# NB - this setting is required to make the app work correctly when running
# via ProxyPass from Apache. Otherwise CSRF checks and some redirects will not
# work.
USE_X_FORWARDED_HOST = True

Django: Problem with template paths?

So after a few hours of irritation i finally got my django site up and running! The only problem i have now is that all the stylesheets/images are linked incorrectly. Or, well, they are linked correctly but django wont give me the files, kind of.
This is how it's set up:
views.py:
from django.shortcuts import render_to_response
def home(request):
return render_to_response('index.html')
urls.py:
from django.conf.urls.defaults import patterns, include, url
urlpatterns = patterns('',
# Examples:
url(r'^$', 'mysite.views.home', name='home'),
)
and that brings up index.html, but none of the other files are shown, like images, stylesheets etc. How do I solve this? I have a feeling it's really easy!? I tried googling, but couldn't find anything.
Thanks in advance,
qwerty
It sounds like what you're looking for is the ability to serve static files.
Basically, you'll need to add a folder somewhere in your project to save the media to. Then, you'll need to edit your urls.py and settings.py files to accommodate access to your new static media directory.
urls.py
urlpatterns = patterns('',
# Examples:
url(r'^$', 'mysite.views.home', name='home'),
(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root':
settings.STATIC_ROOT}),
)
settings.py
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
# Should be the location where you put your static folder.
# Should be different for testing and production environments.
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'media')
# This is assuming that your settings.py file is in path/to/project/ and your
# static files are in path/to/project/media/
Then in your template you can do this:
< img src="/static/my_image.jpg" / >
Or whatever you want. This will work for javascript, css and image files.
Expanding on Shamanu4's comment: what you're asking for is how static files are served. For development purposes, you can use the static file server.
Long term, though, this is not an optimal solution. The easy way is to segregate all your static files and serve them directly through your web browser via a different path. In Apache, this static file path can be inside your Django path if you configure the static path first.
If you need high performance, though, the Django team recommends that you use a lightweight, speed-optimized server (such as lighttpd) to serve static files and another server with WSGI support (such as Apache) to serve Django.
In the Django project I have at work, I have Django served from /djangoprojname/ and static files served from /djangoprojname/static/. On disk, the static directory is at the same level as my Django project's directory. both of which are in a Mercurial repository. Within static/, I have css/, js/, and img/, and within those directories, I have one directory per app, named the same as the app. This keeps things from getting messy.
My django.conf (in /etc/httpd/conf.d on Fedora or RHEL) looks something like:
WSGIDaemonProcess djangoprojname threads=15
WSGISocketPrefix /var/run/wsgi/wsgi
Alias /djangoprojname/static/ /var/www/djangoprojname/static/
Alias /djangoprojname/admin/media/ /usr/lib/python2.6/site-packages/django/contrib/admin/media/
WSGIScriptAlias /djangoprojname /var/www/djangoprojname/django.wsgi
WSGIProcessGroup djangoprojname
<Directory /var/www/djangoprojname>
Order deny,allow
Allow from all
</Directory>
<Directory /usr/lib/python2.6/site-packages/django/contrib/admin/media>
Order deny,allow
Allow from all
</Directory>
For development, I added this to the end of my project's urls.py:
# Only serve static media if in development (runserver) mode.
if settings.IS_DEV:
urlpatterns += patterns('',
url(r'^static/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT,
'show_indexes': True}),
)
settings.IS_DEV is set in my settings.py to True if this is running on a development server. manage.py is modified to set an environment variable if runserver is used, and settings.py checks for this variable. MEDIA_ROOT is set to the path to the static directory.
You are probably having problem with MEDIA_ROOT and MEDIA_URL in your settings.py. Please refer to http://docs.djangoproject.com/en/1.3/ref/settings/#media-root