What does Django do with `MEDIA_ROOT`? - python

What does Django do with MEDIA_ROOT exactly? I never understood it. Since Django itself doesn't serve static media, and you have to set up apache or something similar for it, why does it care in which directory it sits?

You're not the only one who wonders; check out Django ticket #10650. Based on the comments by Django developers there, I think this pretty much sums up what MEDIA_ROOT is used for:
Unfortunately, Django is also at fault for being far too vague in its docs about what
MEDIA_ROOT and MEDIA_URL are used for. Searching through Django's code confirms that
MEDIA_ROOT & MEDIA_URL are used for file upload, and that MEDIA_URL is provided as a
convenience to templates via the default context processors (available when using
RequestContext??).

It appears to be used by some classes in Django as a default -- for instance, FileSystemStorage uses it as the default place to store files.

When you creates a model with ImageField or FileField attributes, you should pass the upload_to argument. That is a relative path will be appended to your MEDIA_ROOT path and there will be save and retrieve that files.

Related

Deliver images in Django from a different path than from its ImageField.url property

I'm porting a web app from PHP (Codeigniter) to Python (powered by Django.) I already migrated the database and am now using Django models. I populated the database with images using Django's ImageField field and the images are in its proper folders under MEDIA_ROOT.
I'm in development so I'm using Django's server to test the web app as I go and I can serve the images through image.url.
image.url serves the image from:
MEDIA_ROOT/folder/subfolder/numberImage_folder_subfolder.jpg
But I need it to be served from MEDIA_ROOT/numberImage_folder_subfolder.jpg.
In production I know I can serve the image using nginx's XSendFile or something like that. Django's server (runserver command) is very easy to use and gives me what I need at the moment. While in development, how can I deliver the image from the URL I require? Preferably using Django's server...
Any help will be so much appreciated.
I'm not entirely clear on what your URLs are and how they map to file paths (and don't have the reputation to ask for clarification yet). So correct me if I've understood it wrong.
But in the meantime, to rephrase the question slightly, I think you're saying that you have the files stored on disk in those subfolders like MEDIA_ROOT/folder/subfolder/numberImage_folder_subfolder.jpg, but when you actually want the URLs served, you don't want the folders in the URL, so the URL will have MEDIA_ROOT/numberImage_folder_subfolder.jpg? And only with the ./manage.py runserver?
Going ahead on those assumptions, we have two steps: map the URLs we want back to a file path, and then also make sure we're generating the URLs we want.
For the first, normally urls.py will have something like this to serve media files in development:
from django.conf.urls.static import static
if settings.DEBUG is True:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
which is basically adding url(r'^media/(?P<path>.*)$', django.views.static.serve) to your urlconf, where serve takes all paths below settings.MEDIA_URL and serves up the equivalent file under MEDIA_ROOT.
The simplest way to do this would be to create a custom function modelled on that same django.conf.urls.static which takes the path and adds the folders back in before passing it on to django.views.static.serve.
For the second, if you want the URLs generated from the ImageField.url to differ from the underlying file storage path, you'll need to have a custom ImageField subclass overriding the FileField.url property (or a custom Storage class that does a similar thing).
Like so:
class CustomURLImageField(django.forms.fields.ImageField):
def _get_url(self):
"""
Override the standard FileField.url property to mangle the URL from
MEDIA_ROOT/folder/subfolder/numberImage.jpg
to
MEDIA_ROOT/numberImage_folder_subfolder.jpg
"""
self._require_file()
#return self.storage.url(self.name)
path_components = self.name.split('/')
folder = path_components[-3]
subfolder = path_components[-2]
numberImage, ext = os.path.splitext(path_components[-1])
return '/{numberImage}_{folder}_{subfolder}{ext}'.format(**locals())
url = property(_get_url)
This will be likely true in production too... how are you generating your URLs?)

Django wrong precedence of templates?

It took me forever to find out why a template was not getting overridden, only to find that it seems Django simply does not use the correct precedence in overriding the templates.
The templates I'm trying to change are the ones for changing the user's password, which are loaded for the URL /accounts/password/change.
I have my modified templates in mysite/myapp/templates/registration; the system default templates are at /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/contrib/admin/templates/registration. When templates are present in both these directories, Django uses the system (/Library) ones. Huh?
When I remove the templates in /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/contrib/admin/templates/registration
, the correct ones (i.e. mine, in mysite/myapp/templates/registration) are loaded.
How to fix this issue? That is, how to make Django load my overridden templates without having the delete the original templates found in the /Library?
you have to create an admin directory inside the templates dir in which you set the templates you want to override
In order to override one or more of them, first create an admin directory in your project’s templates directory. This can be any of the directories you specified in TEMPLATE_DIRS.
Read the Django doc here

Confused about configuring django-avatar for storing avatar

Edit: Some random edits seem to do the work, but I don't understand how.
I have just "installed" the app django-avatar into my django project. (currently, it is under development, so I am using the server which comes with django)
However. after I upload an avatar, neither can I find the avatar in any folder, nor is it being displayed. I am new to django, and python, so I don't know what to do, or which part of my code to post. I am completely clueless. I have set up a url, at which static files are server(via django.views.static.serve)
url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
(settings is imported)
However. I feel this is wrong. I would like some guiding.
Media/Static related settings:
MEDIA_ROOT = 'd:/a4m/media/'
MEDIA_URL = '/media/'
STATIC_ROOT = ''
STATIC_URL = '/static/'
STATICFILES_DIRS = (('d:/a4m/static/'),)
As for templates, I am just using the ones which django-avatar provides.
First, don't add your project's static directory to STATICFILES_DIRS. You shouldn't be manually putting anything in that directory, so there's no reason to serve it in development (which is why Django doesn't by default). Also, I don't think it's related to this issue, but STATIC_ROOT needs a real value, which should be in your case:
STATIC_ROOT = 'd:/a4m/static/'
That said, two things from looking at the django-avatar source:
It uses a setting named AVATAR_STORAGE_DIR, so you should probably define that if you haven't. It seems the following would be sensible:
AVATAR_STORAGE_DIR = MEDIA_ROOT + 'avatars/'
If, for whatever reason, the avatar can't be written to the filesystem, django-avatar returns silently. So, I would check things like permissions to ensure that Django will have no problems writing to any directory under AVATAR_STORAGE_DIR.
Hopefully, that will be enough to get you a further in debugging this issue.

Why absolute paths to templates and css in django ? (Isn't that a bad practice ?)

In django, the documentation asks to use the absolute paths and not the relative paths.
Then, how do they manage portability ?
If I have my template in the project folder then, even a rename of the folder will cause breakage.. !
Then what is the reason behind this practice ?
Please explain ?
Could you post a link to that piece of documentation, please?
In Django you configure, in settings.py, the search path for templates (through TEMPLATE_DIRS variable). Then, inside a view, you render a template naming its file relative to one of the path included in TEMPLATE_DIRS. That way, whenever you move you template dir you just need to modify your settings.py
As for static files, like CSS docs, Django does not need to know anything about them (unless you are serving static files through django itself, which is discouraged by django's documentation): you only need to tell your web server where to find them.
I switch environments from a Linux desktop to a Windows laptop, so hard coding paths won't work for me either.
There may be a better way to do this, but I wrote this function that goes at the top of my settings.py to get the absolute path from a relative path in my project:
#settings.py
import os
def map_path(directory_name):
return os.path.join(os.path.dirname(__file__), \
directory_name).replace('\\', '/')
That allows me to do:
MEDIA_ROOT = map_path('static')
TEMPLATE_DIRS = (
map_path('templates'),
)
"static" and "templates" live under my project root. Hope that helps you out.

Django upload_to outside of MEDIA_ROOT

My deployment script overwrites the media and source directories which means I have to move the uploads directory out of the media directory, and replace it after the upload has been extracted.
How can I instruct django to upload to /uploads/ instead of /media/?
So far I keep getting django Suspicious Operation errors! :(
I suppose another solution might be a symlink?
Many thanks,
Toby.
I did the following:
from django.core.files.storage import FileSystemStorage
upload_storage = FileSystemStorage(location=UPLOAD_ROOT, base_url='/uploads')
image = models.ImageField(upload_to='/images', storage=upload_storage)
UPLOAD_ROOT is defined in my settings.py file: /foo/bar/webfolder/uploads
While the accepted answer is probably what you want, we now have the option with django 3.1 that we can decide which storage to use at runtime by passing a function to the storage argument of an ImageField or FileField.
def select_storage():
return MyLocalStorage() if settings.DEBUG else MyRemoteStorage()
class MyModel(models.Model):
my_file = models.FileField(storage=select_storage)
Have a look at the official docs.
Please note that the current accepted answer writes the actual value of the variable UPLOAD_ROOT to the migration file. This doesn't produce any SQL when you apply it to the database but may be confusing if you change that setting frequently.

Categories

Resources