Django MEDIA_URL and MEDIA_ROOT
UPDATE for Django >= 1.7
Per Django 2.1 documentation: Serving files uploaded by a user during development
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = patterns('',
# ... the rest of your URLconf goes here ...
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
You no longer need if settings.DEBUG
as Django will handle ensuring this is only used in Debug mode.
ORIGINAL answer for Django <= 1.6
Try putting this into your urls.py
from django.conf import settings
# ... your normal urlpatterns here
if settings.DEBUG:
# static files (images, css, javascript, etc.)
urlpatterns += patterns('',
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT}))
With this you can serve the static media from Django when DEBUG = True
(when you run on local computer) but you can let your web server configuration serve static media when you go to production and DEBUG = False
MEDIA_ROOT vs MEDIA_URL (Django)
First of all, I explain about "MEDIA_ROOT" then "MEDIA_URL".
<MEDIA_ROOT>
"MEDIA_ROOT" sets the absolute path to the directory where uploaded files are stored and setting "MEDIA_ROOT" never ever influence to media file URL.
For example, we have a django project:
Then, we set "os.path.join(BASE_DIR, 'media')" which is "C:\Users\kai\django-project\media" in Windows in my case to "MEDIA_ROOT":
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # Here
MEDIA_URL = '/media/'
And set the code below to "urls.py":
# "core/urls.py"
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
And set the model "Image" as shown below:
# "myapp/models.py"
class Image(models.Model):
image = models.ImageField()
def __str__(self):
return str(self.image)
And set the code below to "admin.py":
# "myapp/admin.py"
from .models import Image
admin.site.register(Image)
Then, upload the file "orange.jpg":
Then, "media" folder is created at the same level as "db.sqlite3" and "manage.py" which is just under the django project root directory and the uploaded file "orange.jpg" is stored in "media" folder as shown below:
Then, upload more files:
In addition, we can display the file "orange.jpg" by clicking on "orange.jpg" on "Change image" page of the file as shown below:
Then, the file "orange.jpg" is displayed as shown below:
Be careful, if you remove the code below from "urls.py":
# "core/urls.py"
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Then, the file "orange.jpg" is not displayed. Instead, there is an error as shown below:
Next, you can store uploaded files under more subdirectories and I explain 2 ways to do that and the first way is recommended because it is flexible and the second way is not recommended because it is not flexible at all.
The first way to store uploaded files under more subdirectories is
first, set "os.path.join(BASE_DIR, 'media')" to "MEDIA_ROOT" as shown below:
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # Here
MEDIA_URL = '/media/'
And, add "upload_to='images/fruits'" to "models.ImageField()" as shown below:
# "myapp/models.py"
from django.db import models
class Image(models.Model): # Here
image = models.ImageField(upload_to='images/fruits')
def __str__(self):
return str(self.image)
Then, uploaded files are stored in "C:\Users\kai\django-project\media\images\fruits" in Windows in my case as shown below:
The second way to store uploaded files under more subdirectories is first, set 'media/images/fruits' to the second argument of "os.path.join()" as shown below:
# "core/settings.py"
# Here
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/images/fruits')
MEDIA_URL = '/media/'
And set no arguments to "models.ImageField()" as shown below:
# "myapp/models.py"
from django.db import models
class Image(models.Model):
image = models.ImageField() # Here
def __str__(self):
return str(self.image)
Then, uploaded files are stored in "C:\Users\kai\django-project\media\images\fruits" in Windows in my case as shown below but as I said before, the first way is recommended because it is flexible while the second way is not flexible at all:
In addition, if we don't set "MEDIA_ROOT" as shown below:
# "core/settings.py"
# MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # Here
MEDIA_URL = '/media/'
Or set an empty string to the second argument of "os.path.join()" as shown below:
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, '') # Here
MEDIA_URL = '/media/'
Or don't set the second argument of "os.path.join()" as shown below:
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR) # Here
MEDIA_URL = '/media/'
And set no arguments to "models.ImageField()" as shown below:
# "myapp/models.py"
from django.db import models
class Image(models.Model):
image = models.ImageField() # Here
def __str__(self):
return str(self.image)
Then, uploaded files are stored at the same level as "db.sqlite3" and "manage.py" which is just under the django project root directory as shown below:
In addition, after uploading files if we change "MEDIA_ROOT", we cannot display uploaded files while we can still display uploaded files even if we change "models.ImageField()".
For example, we set "os.path.join(BASE_DIR, 'media')" to "MEDIA_ROOT":
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # Here
MEDIA_URL = '/media/'
And, set "upload_to='images/fruits'" to "models.ImageField()" as shown below:
# "myapp/models.py"
from django.db import models
class Image(models.Model): # Here
image = models.ImageField(upload_to='images/fruits')
def __str__(self):
return str(self.image)
Then, upload the file "orange.jpg":
Then, click on "images/fruits/orange.jpg" on "Change image" page of the file as shown below:
Then, the file "orange.jpg" is displayed as shown below:
Now, we change "MEDIA_ROOT" from "os.path.join(BASE_DIR, 'media')" to "os.path.join(BASE_DIR, 'hello/world')":
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, 'hello/world') # Here
MEDIA_URL = '/media/'
Then again, click on "images/fruits/orange.jpg" on "Change image" page of the file as shown below:
Then, the file "orange.jpg" is not displayed. Instead, there is an error as shown below:
Then, as I said before, even if we change "models.ImageField()" after uploading files, we can still display uploaded files. So now, we change back "MEDIA_ROOT" from "os.path.join(BASE_DIR, 'hello/world')" to "os.path.join(BASE_DIR, 'media')":
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # Here
MEDIA_URL = '/media/'
And, change "models.ImageField(upload_to='images/fruits')" to "models.ImageField(upload_to='hello/world')":
# "myapp/models.py"
from django.db import models
class Image(models.Model): # Here
image = models.ImageField(upload_to='hello/world')
def __str__(self):
return str(self.image)
Then again, click on "images/fruits/orange.jpg" on "Change image" page of the file as shown below:
Then, the file "orange.jpg" is displayed as shown below:
<MEDIA_URL>
Next, I explain about "MEDIA_URL".
"MEDIA_URL" sets the directory(middle) part of media file URL between the host part and the file part of media file URL as shown below and setting "MEDIA_URL" never ever influence to the absolute path to the directory where uploaded files are stored:
Host Directory File
| | |
<-------------> <----------> <-------->
https://www.example.com/media/images/orange.jpg
For example, we set '/media/' to "MEDIA_URL":
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/' # Here
And set no arguments to "models.ImageField()" as shown below:
# "myapp/models.py"
from django.db import models
class Image(models.Model):
image = models.ImageField() # Here
def __str__(self):
return str(self.image)
Then, upload the file "orange.jpg":
Then, go to "Change image" page of the file then click on "orange.jpg":
Then, the URL of the file is displayed as shown below:
As you can see, the directory part "media" is set between the host part "localhost:8000" and the file part "orange.jpg"
Host Directly File
| | |
<------------> <---> <-------->
http://localhost:8000/media/orange.jpg
And, this URL below is in this case of "www.example.com" with "https":
Host Directly File
| | |
<-------------> <---> <-------->
https://www.example.com/media/orange.jpg
And, we can change the directory part of URL even after uploading files.
So, just change "MEDIA_URL" from '/media/' to '/images/fruits/' as shown below:
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/images/fruits/' # Here
Then, click on "orange.jpg" again:
Then, the directory part "media" is changed to "image/fruits" as shown below:
In addition, we can set the directory part of URL with the combination of "MEDIA_URL" and "models.ImageField()". In this case, we can only change the part of the directory part set by "MEDIA_URL" after uploading files while we cannot change the part of the directory part set by "models.ImageField()" after uploading files:
For example, we set '/media/' to "MEDIA_URL" as shown below:
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/' # Here
And add "upload_to='images/fruits'" to "models.ImageField()" as shown below:
# "myapp/models.py"
from django.db import models
class Image(models.Model): # Here
image = models.ImageField(upload_to='images/fruits')
def __str__(self):
return str(self.image)
Then, upload the file "orange.jpg":
Then, go to "Change image" page of the file then click on "images/fruits/orange.jpg":
Then, the URL of the file is displayed as shown below:
Then, the directory part is:
media/images/fruits
Now, we change "MEDIA_URL" from '/media/' to '/hello/world/':
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/hello/world/' # Here
And, change "models.ImageField(upload_to='images/fruits')" to "models.ImageField(upload_to='hey/earth')":
# "myapp/models.py"
from django.db import models
class Image(models.Model): # Here
image = models.ImageField(upload_to='hey/earth')
def __str__(self):
return str(self.image)
Then, click on "images/fruits/orange.jpg" again:
Then, the URL of the file is displayed as shown below:
Then, we could change the part of the directory part 'media' to 'hello/world' set by "MEDIA_URL" after uploading the file "orange.jpg" while we couldn't change the part of the directory part 'images/fruits' to 'hey/earth' set by "models.ImageField()" after uploading the file "orange.jpg":
hello/world/images/fruits
In addition, if we don't set "MEDIA_URL" as shown below:
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# MEDIA_URL = '/media/' # Here
Or set an empty string to "MEDIA_URL" as shown below:
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '' # Here
Or set one or more slashes to "MEDIA_URL" as shown below:
# "core/settings.py"
MEDIA_ROOT = os.path.join(BASE_DIR)
MEDIA_URL = '/////' # Here
And set no arguments to "models.ImageField()" as shown below:
# "myapp/models.py"
from django.db import models
class Image(models.Model):
image = models.ImageField() # Here
def __str__(self):
return str(self.image)
Then, no directory part is set between the host part "localhost:8000" and the file part "orange.jpg" as shown below:
http://localhost:8000/orange.jpg
Django - MEDIA_ROOT and MEDIA_URL
The MEDIA_ROOT
is the path on the filesystem to the directory containing your static media.
The MEDIA_URL
is the URL that makes the static media accessible over HTTP.
The docs: http://docs.djangoproject.com/en/1.2/ref/settings/#media-root
The main idea is that serving things through python+django is expensive. Since your media is static you don't need to pay that cost, so you serve it differently (e.g. directly via nginx or through a CDN). However, you still need to know where the media is located in the file system (e.g. for file uploads) and what the URL is (e.g. to put in templates). The settings exist to tie all that together.
Why should you not use the MEDIA_ROOT and MEDIA_URL in the production level of Django?
There's nothing wrong with those variables in particular. The fact is you never want to serve static files using Django's dev server in production, both because of performance and security issues.
The dev server is very helpful, because it allows you to use nothing but Django to serve static files and media files during development, but it is not a production web server in any way (such as Nginx for example).
The docs are, as always, helpful: https://docs.djangoproject.com/en/3.1/howto/static-files/#serving-uploaded-files-in-development
What applies to static files also applies to media files. For strategies about static files deployment, there's a whole page on the docs too.
Some packages, such as Whitenoise, help when dealing with static files in production, but Whitenoise can't be used for media (user-uploaded) static files (because roughly it discovers static files at start).
The real difference between MEDIA_ROOT (media files) and STATIC_ROOT (static files) in python django and how to use them correctly
Understanding the real difference between MEDIA_ROOT
and STATIC_ROOT
can be confusing sometimes as both of them are related to serving files.
To be clear about their differences, I could point out their uses and types of files they serve.
STATIC_ROOT, STATIC_URL and STATICFILES_DIRS
are all used to serve the static files required for the website or application. Whereas,MEDIA_URL and MEDIA_ROOT
are used to serve the media files uploaded by a user.
As you can see that the main difference lies between media and static files. So, let's differentiate them.
- Static files are files like CSS, JS, JQuery, scss, and other images(PNG, JPG, SVG, etc. )etc. which are used in development, creation and rendering of your website or application. Whereas, media files are those files that are uploaded by the user while using the website.
So, if there is a JavaScript file named main.js
which is used to give some functionalities like show popup on button click then it is a STATIC file. Similarly, images like website logo, or some static images displayed in the website that the user can't change by any action are also STATIC files.
Hence, files(as mentioned above) that are used during the development and rendering of the website are known as STATIC files and are served by STATIC_ROOT, STATIC_URL or STATICFILES_DIRS(during deployment) in Django.
Now for the MEDIA files: any file that the user uploads, for example; a video, or image or excel file, etc. during the normal usage of the website or application are called MEDIA files in Django.
MEDIA_ROOT and MEDIA_URL are used to point out the location of MEDIA files stored in your application.
Hope this makes you clear.
django MEDIA_ROOT and MEDIA_URL TEMPLATES
There are a few things that could be going on here:
- You're running a non-development web server that hasn't been setup to serve static media. The solution here will vary depending on what web server you're running.
- You're running the development web server and haven't setup static serving. For this, I'd add the following to your root urls.py file:
urlpatterns = [
# ... the rest of your URLconf goes here ...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
- There's a permissions issue in your MEDIA_ROOT directory. In this case, I'd make sure your MEDIA_ROOT directory is readable by your web server.
Django 3.0 MEDIA_ROOT and MEDIA_URL raise ImproperlyConfigured exception
You have a typo:
MEIDA_URL
It should be:
MEDIA_URL
Related Topics
How to Compare Version Numbers in Python
How to Set Sys.Stdout Encoding in Python 3
Using Lambda Expression to Connect Slots in Pyqt
Single VS Double Quotes in JSON
Rewrite Multiple Lines in the Console
Printing All Instances of a Class
Getting Syntaxerror for Print with Keyword Argument End=' '
Setup Script Exited with Error: Command 'X86_64-Linux-Gnu-Gcc' Failed with Exit Status 1
Python Selenium Wait for Several Elements to Load
How to Display Pandas Dataframe of Floats Using a Format String for Columns
Python Requests Library Redirect New Url
How to Bind Self Events in Tkinter Text Widget After It Will Binded by Text Widget
Why Python 3.6.1 Throws Attributeerror: Module 'Enum' Has No Attribute 'Intflag'
Convert Pandas Timezone-Aware Datetimeindex to Naive Timestamp, But in Certain Timezone