How to upload images to Django media without subdirectory - django

I need to upload an image to a Django ImageField, but due to a restriction based on a third party API, I need the images to be uploaded to the media directory without a subdirectory.
The restriction is due to the fact that the filename stored locally (in the imagefield column) is used to calculate a hash to request that image from a media API, so the field must contain the same name as the filename in the API, unfortunately the API filename cannot contain slashes.
I can't add a field to the db to store the real filename, nor can I control the code that returns the calculated hash.
I tried making the upload_to a callable that returns an empty string, which seems to get around the upload_to required error, but the images are all then saved as just ''(blank) _1, _2 ... etc without the rest of the image name.
I have also tried making the upload_to return '/', '../media', '../media/' all to no avail (a variety of errors or malformed filenames)
So TL;DR how to save images directly to MEDIA_ROOT, without a sub directory?
EDIT, extra info:
So I just tried a little hack that does part of it:
from django.core.files.storage import FileSystemStorage
media_root_store = FileSystemStorage(location='/path/to/media/parent')
class MyModel(models.Model):
img_file = models.ImageField(
max_length=255,
upload_to='media',
storage=media_root_store)
This dirty hack saves the image to the correct location, though it still obviously saves the image path with media/ appended. So I'm unsure if it has actually gotten me any closer.

Turns out there was a pretty big clue in the error from my earlier attempt (the one generating _1, _2 etc)
If I specify an upload_to callable that simply returns the filename argument, then the image will be saved directly in the MEDIA_ROOT, with the correct filename saved in the database (without the directory prefix).
I had been under the impression that upload_to will just provide a path to append to MEDIA_ROOT, which will then have the image filename appended to that. Turns out this is incorrect.

Related

REST framework's FileField: How can I force using TemporaryUploadedFile

I want to extract and process text from a text document uploaded by the user without actually saving the document. I use Django's REST framework and I want this to happen in the serializer.
I get the document from a FileField. Because the text document is likely to be small, it will be wrapped into InMemoryUploadedFile automatically. However, text-extraction modules (e.g. docx2python) need to open files from paths, not from memory.
How can I turn an InMemoryUploadedFile into a TemporaryUploadedFile, so I can get a path to use? Or how do I force a particular field (without changing the app settings) to always wrap a file in TemporaryUploadedFile?

Upload files to dynamic folders using random string in models.Filefield 'upload_to' entry

I am using models.Filefield to upload files to the server. When uploading a new file with name of an existing file, django append name with some random characters. But I need to retain filename. Hence I change upload_to entry in the models.Filefield to upload_to='str(uuid.uuid4())'. It works fine, but seldom the above problem occur. Is there any other methods to correct it ?

To use Django FileField or FilePathField?

I'm a bit confused about which field to use. What I need is just a Field that will hold a file (audio and/or another one for an image)
The FileField seems to be specifically for uploading and I think it is a bit of overkill for what I need, I also don't like how it will automatically upload and rename the files to a unique filename (file_FHjgh758.txt) everytime something is uploaded.
The problem I have with the FilePathField is that it seems to require an absolute path, which would obviously be different from dev to production, I got around this by adding this to the model...
import os
class Foo(models.Model):
path = os.path.dirname(os.path.dirname(__file__))
path = os.join(path, 'media')
audio = models.FilePathField(path=path)
I have no idea if this is safe or proper, and there aren't many examples online or in the docs to draw from.
To be clear, I just want to have a field which I can point to a file (audio or image) somewhere in my system. What would be the best way to go about doing this?
If you want to refer to files that are already on your filesystem rather than user uploaded files, then FilePathField is the one that you want.
In this regard a few comments:
Don't point to a path that is inside your app's source tree. That is not safe.
You can use settings or environment variables to handle development vs. production paths, e.g., put a FILE_PATH_FIELD_DIRECTORY setting in your development/production settings files and refer to this setting from your app:
from django.conf import settings
class Foo(models.Model):
audio = models.FilePathField(path=settings.FILE_PATH_FIELD_DIRECTORY)

django sorl-thumbnail inverse function of get_thumbnail()

I'm trying to set up permission checking to static files uploaded by users. To do this, I use the path requested to get the media object which represents the file. I also use sorl-thumbnail library to make thumbnails. I use get_thumbnail() function to get the cached thumbnail from an url of the original uploaded picture. Is there any way of doing the inverse operation? from a cached image url, can i have the original url? something like:
picture = Image.objects.get(url=get_original('/cached/url/of/the/thumbnail/image'))
There is no default way to do this. Sorl thumbnail generates the path for the new thumbnail by creating a hash of the original file name along with the options you have specified so there is no easy way to reverse that operation. You could create a DB table the maps the original image file to your current thumbnail and keeps it up to date everytime the dimensions etc. change.

Django: Saving a file from disk with FileField

In my app I parse some xml which contains a path to an image file. Now if I am passing the path to the property of my model which is a FileField it's not copying the file using the upload_to settings. I also tried to pass it a stream of that file but that raised an exception.
How do I use the FileField with data that isn't coming from a request?
Assuming the file is in your MEDIA_ROOT (If it's outside of MEDIA_ROOT you'll get SuspiciousOperation errors):
m = YourModel(file='uploads/file.txt')
If you already have the file on your system, it'd surely be easier to just move it to your uploads directory. You could always customize FileField to handle moving the file for you.