Accessing "Media" files in Django - django

I'd like to love Django, but this business of static and media files in development environments is driving me nuts. Please rescue me from my stupidity.
I'm on my development machine. I have folder media in the root of my project directory.
In settings.py I have: MEDIA_ROOT = '' and MEDIA_URL = '/media/'.
In urls.py I have:
if settings.DEBUG:
urlpatterns += patterns('',
url(r'^media/(?P<path>.*)$',
'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, }),
)
But the only way I can get media files is by referencing /media/media/ e.g.
<img src="/media/media/image.png" />.
I expect (and want)
<img src="/media/image.png" />
Can anyone tell me what is happening here, and give me a simple recipe for setting up media file handling?
Thank you very much.
#Timmy O'Mahony - thanks! epic post, and very clear. But it leaves a couple of questions:
(1) I have to use /media/ and /static/, not media/ and static/ as MEDIA_URL and and STATIC_URL - am I missing something?
(2) If collectstatic hoses /static/, where do you put site level CSS e.g. the site's CSS files? Not in /static/, evidently.
(3) I put them in a directory '_' off the project root and set STATICFILES_DIRS to point to it - and that seems to be where the development server gets its static files, despite the urlpatterns directive. If THAT is wrong, where do you put site level CSS during development, and what is the workflow around collectstatic when you modify them - do you have to edit them one place, and collect them someplace else after every edit?

Folder Setup:
Your project root should be something like:
/app1
/app2
/media
/static
/templates
urls.py
settings.py
manage.py
The media folder is supposed to hold things like images, downloads and other material that might be uploaded during normal use of the website (i.e. after development is finished)
The static folder is supposed to hold all the CSS/JS and other material that is a part of the development of the site
Settings.py:
MEDIA_ROOT is the absolute server path to the static folder mentioned above. That means it should be something like:
MEDIA_ROOT = "/User/Bob/Sites/MySite/Project_root/media/"
MEDIA_URL is the relative browser URL you should access your media files from when you are looking at the site. It should be (usually)
MEDIA_URL = "media/"
which means all material can be viewed at http://example.com/media/
Similarly, STATIC_ROOT should be something like
STATIC_ROOT = "/User/Bob/Sites/MySite/Project_root/static/"
and STATIC_URL be
STATIC_URL = "static/"
Serving the files:
Now that you have told django where these folders should be, and the correct URLs to access them, you need to serve all requests to the folders correctly.
Usually when you are in production, you want the webserver to take care of serving your static files and media files.
If you are developing though, you can just get the django development server to serve them for you.
To do this, you tell it to route all request that come in to http://example.com/media to your MEDIA_ROOT and all requests that come in to http://example.com/static to your STATIC_ROOT.
To do this, you add some URLS to URLS.py like you have:
from django.conf import settings
if settings.DEBUG:
urlpatterns += patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT,
}),
url(r'^static/(?P<path>.*)$', 'django.views.static.serve', {
'document_root': settings.STATIC_ROOT,
}),
)
Extra:
If you have multiple apps, each with their own CSS and JS files, you mightn't want to throw them into one single /static/ folder. It might be useful to put them in subfolders of the apps they belong to:
/app1/static/ # Specific static folder
/app2/static/
/media/
/static/ # Root static folder
Now, your webserver/development server is only looking for static files where you told it to look (i.e. the root static folder) so you need to collect all the files in the subfolders and copy them to the root static folder. You could do this by hand, but django provides a command to do this for you (this is the whole point of the static app)
./manage collectstatic

Why have you made the MEDIA_ROOT setting blank? It needs to be the path to your media directory. Since, as you say, your media is in a subdirectory called media, you should put that in MEDIA_ROOT.

I followed timmy procedure but I got an error that No module name django.views. When I use import django.views in my virtualenv everything works fine i.e It's not an issue with the import of library.
However, I was able to solve this problem by following this procedure in my main urls file
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
https://docs.djangoproject.com/en/dev/howto/static-files/

I had the same problem so I added these lines
from django.conf.urls import url, include
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
url(r'', include('blog.urls')),
url(r'^admin/', admin.site.urls),
url(r'^cadmin/', include('cadmin.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
in urls.py in the Django project configuration directory. more information :https://overiq.com/django/1.10/handling-media-files-in-django/

In your settings.py, make sure you add
django.core.context_processors.media
in your TEMPLATE_CONTEXT_PROCESSORS.Otherwise the MEDIA_ROOT won't work when you use it in the templates.

I am using Django 1.10. And my media folder is 'uploads'
This is the configuration in my settings.py:
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
MEDIA_URL = '/uploads/'
And in the template I put the name o my MEDIA_URL before de object.name instead object.url like this:
<img src="uploads/{{ imagen_identificativa.name }} " alt="{{imagen_identificativa}}">
And it works for me.
I hope this helps.

For Django version 3 I used the following:
from django.conf import settings
from django.urls import re_path
from django.views.static import serve
# ... the rest of your URLconf goes here ...
if settings.DEBUG:
urlpatterns += [
re_path(r'^media/(?P<path>.*)$', serve, {
'document_root': settings.MEDIA_ROOT,
}),
]
my settings.py
BASE_DIR = Path(__file__).resolve().parent.parent
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
STATIC_URL = '/static/'
here is a documentation link https://docs.djangoproject.com/en/3.1/ref/views/
In case you are using Django REST with some dev server don't forget to update your dev proxy settings to redirect /media to Django backend

Here is another alternative:
Set your media configs something like this inside 'settings.py':
#Set media path
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
MEDIA_URL = '/media/'
Lets say I have a modal called person with image filed like below:
class Person(models.Model):
name = models.CharField(max_length = 30)
photo = models.ImageField(upload_to = 'photos')
Now here upload_to path we are taking about is inside the MEDIA_ROOT folder. In my case a media folder will be created inside which photos folder will be created and our media here will be dumped.
So now in my template I do something like this:
<img src="{{ person.photo.url}} />
So in short, you got a field, use it like this:
src ={{ object.field.url}}
Hope that helps! Happy Coding!

Related

Django STATIC_URL with full domain breaks static assets locally

When working locally on a Django project that uses static files and the default static files backend, I am running into an issue when I want to get full absolute urls to the static files instead of only the path.
My settings:
DEBUG = True
BASE_DIR = Path(__file__).resolve().parent.parent
INSTALLED_APPS = ["django.contrib.staticfiles", ...]
STATIC_ROOT = BASE_DIR / "static_root"
STATIC_URL = "/static/"
MEDIA_ROOT = BASE_DIR / "media_root"
MEDIA_URL = "/media/"
STATICFILES_DIRS = (BASE_DIR / "static",)
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
)
Everything works, the admin's CSS is loaded, images work, etc. But when I get the path of a file with this code:
from django.contrib.staticfiles.storage import staticfiles_storage
static_path = staticfiles_storage.url("path_to_folder/some_file.jpg")
That result is a relative path: /static/path_to_folder/some_file.jpg. This is a problem when these urls are used from my external frontend: it now has to prepend the backend's base url to all static assets. But if I'd want to deploy the static assets to S3 for example, in production, then I should not prepend these paths with the domain of the backend.
So what I tried to do was to change the STATIC_URL setting to http://localhost:8000/static/. That way the full url is passed to the frontend, but I could really easily change this setting in the backend in production.
And this is where the problem rears its head: when I change STATIC_URL to http://localhost:8000/static/, none of my static files work anymore, I just get a 404. The admin page also is completely unstyled because of this.
So, to make a long story short: how can I use an absolute STATIC_URL in local development mode with DEBUG=True?
I have created a reproduction repro: https://github.com/kevinrenskers/django-problem-repro.
Found the solution here: https://docs.djangoproject.com/en/4.1/ref/contrib/staticfiles/#django.contrib.staticfiles.views.serve.
Simply add this to the end of urls.py:
from django.conf import settings
from django.contrib.staticfiles import views
from django.urls import re_path
if settings.DEBUG:
urlpatterns += [
re_path(r'^static/(?P<path>.*)$', views.serve),
]
Then the static files will work again even with an absolute URL as the STATIC_URL setting.

Django Rest Framework Routing for embedded Angular Applications

I'm trying to bundle an Angular app and deploy it as static content in a Django Rest Framework DRF application.
I don't know Django or DRF at all however, I want to take control of the routing to express something like this:
For /admin/* - delegate to built-in Django admin.
For /api/* - delegate to Django Rest Framework
For / only, and /* - treat as static content loaded from "some specified project folder", so
/ maps to file ./static/index.html
/assets/pic.jpg maps to ./static/assets/pic.jpg
I've not been able to achieve the above. All I have is this:
A template view for index.html living at ./templates/index.html - This is the from the Angular project and is not a Django template.
Other webpack bundled content copied manually to ./static such as vendor.|hash|.bundle.js
Another problem is what to do with Assets. In the angular project, HTML views refer to assets via /assets which is at the same level as index.html
I've gotten some control over paths using this command line:
ng build --deploy-url=/static --output-path=../backend/tutorial/static
The deploy-url arg results in bundled assets references in index.html being prefixed by /static which means that Django can serve them (but not favicon.ico for some reason).
The output-path arg dumps all the assets somewhere other than the default "dist" folder.
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^api/', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^', TemplateView.as_view(template_name="index.html")),
]
Url patterns looks like the above.
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static")
]
STATIC_URL = '/static/'
These are the static settings. What I need is to be able to say "/static" and "/assets" are both static asset folders.
I'm not sure what TemplateView is (urlPatterns). Maybe there's a StaticFilesView or something that maps a URL to a path on disk?
Blockquote
These are the static settings. What I need is to be able to say "/static" and "/assets" are both static asset folders.
Blockquote
You can achieve that with the following steps:
Add /assets static directory in NGINX site configuration file:
server {
....
....
# your Django project's static files - required
location /static {
alias /path/to.../static;
}
# your Angular project's static files
location /assets {
alias /path/to.../assets;
}
....
....
}
In your Django urls.py add:
from django.views.static import serve as static_serve
urlpatterns = [
....
url(r'^assets/(?P<path>.*)$', static_serve,
{'document_root':'/path/to.../assets'}),
....
....
]
That's it. You don't have to touch the static configuration in Django settings.
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(DATA_DIR, 'media')
STATIC_ROOT = os.path.join(DATA_DIR, 'static')
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'reservation_exchange', 'static'),
)

Django dev server STILL won't serve static files

Okay, all. I know this is a question that many people have solved in various cases, but I cannot for the life of me get my Django 1.9 development server to serve static content on my local computer. Static files worked fine pre-deployment, and are totally fine on my deployment server, but now in my test environment (local computer with runserver going) everything is broken, and I really need to be able to test stylesheets in a dev environment.
I have tried all of these solutions and more, followed the documentation guide, used collectstatic again in the development repo... nothing has worked, and I am at my wits' end.
Currently, I have DEBUG = True, and the following setup:
Folder Hierarchy
project/
manage.py
(&c)
app/
urls.py
models.py
(&c)
project/
settings.py
urls.py
(&c)
static/
styles/
images/
(&c)
settings.py Static Files Settings
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = (
os.path.join(STATIC_ROOT, 'styles/'),
os.path.join(STATIC_ROOT, 'js/'),
os.path.join(STATIC_ROOT, 'audio/'),
os.path.join(STATIC_ROOT, 'images/'),
os.path.join(STATIC_ROOT, 'admin/'),
os.path.join(STATIC_ROOT, 'documents/'),
)
urls.py URL Patterns
from django.conf.urls import include, url, patterns
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
urlpatterns = [
# ... project url patterns blah blah ...
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += patterns('', (r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root':settings.STATIC_ROOT, 'show_indexes': True}))
I also have {% load staticfiles %} in my templates along with the appropriate {% static %} calls (ex: {% static 'styles/main.css' %}).
For reference, the command line gives me the following when I load the page:
"GET /static/styles/main.css HTTP/1.1" 404 1759
If anyone knows of a fix I have missed that might even remotely have a snowball's chance of working, please let me know. It's driving me bonkers not being able to test properly.
EDIT: As suggested, I have updated to Django 1.11 on my local machine, with no changes to the current issue.
I'm not able to test it out, but maybe try changing this:
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
to this:
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
By the way, version 1.9 is unsupported and also a security risk. You'd probably want to upgrade to another version.
Can you try to create the STATIC_ROOT var with the absolute path and check if it works?
Maybe the construction of that var is not OK.
You could also check the STATIC_ROOT var through
python manage.py shell
and see if it correctly fits your path.

Static files status' 404

I'm using heroku to host my Django(1.6) app (called 'Zen'). The problem is static files aren't showing. In other words, there's no CSS and no JS in my app because it doesn't found those files. I looked to other questions here and I configured my app as below:
Settings.py:
##### Static asset configuration #####
STATIC_ROOT = 'staticfiles'
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
urls.py:
from django.conf.urls.static import static
from zen import settings
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL,
document_root=settings.STATIC_ROOT)
urlpatterns += patterns('',
(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),
)
wsgi.py:
import os
from django.core.wsgi import get_wsgi_application
from dj_static import Cling
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "zen.settings")
application = Cling(get_wsgi_application())
Apparently, after pushing my app with git push heroku master all is working great:
-----> Preparing static assets
Running collectstatic...
69 static files copied to '/app/staticfiles'.
But as you can see there is no CSS in my app (http://obscure-reef-8874.herokuapp.com/). I looked to my app's log and mostly css and js files are in 404 status... I tried everything, can you help me?
EDIT:
I didn't find the bug, I recreated an app and it worked, simple.
Set
STATIC_ROOT = 'static'
try
May be caused by different STATIC_ROOT and STATICFILES_DIRS
The problem is not with your static file serving: that is fine, as you can see if you go to the admin application: http://obscure-reef-8874.herokuapp.com/admin/. Files under /static/admin/ are being served with no problem.
Without seeing the structure of your application and the way you are outputting the static links in your template it's hard to help, I guess that your files are inside a subdirectory of /static/, so you'll need to reference that subdirectory in the links to the assets in your template.
Note that you should remove the additional static URL patterns from your urls.py. They do not work when DEBUG is False. Your files are served by Cling, which is external to Django.

Django Avatars referencing images by absolute file system path on local (django-avatar)

I am trying to install django-avatar in my Django installation. What I cannot figure out for the life of me is where I'm going wrong with the MEDIA_ROOT and MEDIA_URL paths.
Avatars are currently being uploaded to the correct location on my local: <* project *>/media/avatars/...
However, when I hit /avatars/change/ the Images are being served using local absolute paths:
/Users/<* username >/< project_path *>/media/avatars/....jpg
In my settings.py I have the following variables set:
PROJECT_PATH = os.path.realpath(os.path.dirname(__file__))
MEDIA_ROOT = os.path.join(PROJECT_PATH, 'media')
MEDIA_URL = '/media/'
AVATAR_STORAGE_DIR = MEDIA_ROOT + '/avatars/'
And in my urls.py I have:
if settings.DEBUG:
urlpatterns += patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT,
}),
url(r'^static/(?P<path>.*)$', 'django.views.static.serve', {
'document_root': settings.STATIC_ROOT,
}),
)
I think the problem must be at the application level rather than in my project settings. If anyone could help that would be amazing!
From my experience, this is standard behavior when using the development server. The Django development server is serving the static files and does so from the MEDIA_ROOT (the full local path).
When deploying, static files should be served with your web server and the URL's will reflect the MEDIA_URL you're expecting.
May be worth reading over Django's docs on managing static files.