Django Media_Url and Media_Root

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:

Sample Image

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":

Sample Image

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:

Sample Image

Then, upload more files:

Sample Image

In addition, we can display the file "orange.jpg" by clicking on "orange.jpg" on "Change image" page of the file as shown below:

Sample Image

Then, the file "orange.jpg" is displayed as shown below:

Sample Image

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:

Sample Image

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:

Sample Image

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:

Sample Image

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:

Sample Image

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":

Sample Image

Then, click on "images/fruits/orange.jpg" on "Change image" page of the file as shown below:

Sample Image

Then, the file "orange.jpg" is displayed as shown below:

Sample Image

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:

Sample Image

Then, the file "orange.jpg" is not displayed. Instead, there is an error as shown below:

Sample Image

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:

Sample Image

Then, the file "orange.jpg" is displayed as shown below:

Sample Image

<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":

Sample Image

Then, go to "Change image" page of the file then click on "orange.jpg":

Sample Image

Then, the URL of the file is displayed as shown below:

Sample Image

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:

Sample Image

Then, the directory part "media" is changed to "image/fruits" as shown below:

Sample Image

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":

Sample Image

Then, go to "Change image" page of the file then click on "images/fruits/orange.jpg":

Sample Image

Then, the URL of the file is displayed as shown below:

Sample Image

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:

Sample Image

Then, the URL of the file is displayed as shown below:

Sample Image

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:

Sample Image

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.

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

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

  1. 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.
  2. 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)

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



Leave a reply



Submit