django sorl-thumbnail inverse function of get_thumbnail() - django

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.

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?

Django: Accept zip file having multiple image files in it through a Django form as FileField and operate on it

Class X(models.Model):
zip_file = models.FileField()
Now, this zip_file is a zip having any number of images. I want to be able to extract all the images and save (to DB) them under the same X object i.e. the "primary key" is the same.
I understand that the File is stored in the system and only a reference is stored in the DB and I am fine with it.
I am unsure about what is the best practice to unzip the file at the
server and save them one by one to the DB.
One naive idea I have is using the "validators" to check the files and save them to DB but unsure if that is a best practice.
Any help or suggestion is appreciated. :)
There are a few different ways that you can approach this, based on the requirements and number of images that are in the zip file. I am going to make the following assumptions:
You want to keep the zip file
There are an arbitrary number of image files in each zip file
In this case, then you can format your model as below. Once you finish the file upload process, you can trigger a signal or background task to parse the zip file, and for each image file, create a separate object that is related to the zip file through a foreign key. This would allow you to easily grab all of the files without having to create a number of image fields.
[models.py]
class X(models.Model):
zip_file = models.FileField()
class XImages(models.Model):
image = models.ImageField()
x = models.ForeignKey(X)
In the case where you don't actually care about keeping the zip file, then you can do something similar, but instead of saving the object on the form post, you can simply extract it then, and save the images in the separate class.
If there are a static number of images in each zip file, then you can simply create that specific number of ImageFields in the model itself.

If I change ImageFIeld.upload_to parameter, should it move previously uploaded files upon migration?

I have a Django model with
...
image = models.ImageField(default=None, upload_to=settings.PHOTO_UPLOAD_TO)
...
I have changed the value of settings.PHOTO_UPLOAD_TO, but the files have remained where they were, and the database entries also don't seem to have changed. A newly added image is placed in the correct new location, but not the old ones. Is it an expected behaviour? Is there a way to migrate the image locations? I would like to slightly change the directory/URL structure of my project.
The path of a FileField/ImageField is stored relative to MEDIA_ROOT, so if you want to move the files to the new upload_to folder, you're gonna need to put that in your migration yourself (like you suggested).

Getting file uploads to work with Django & Cloudinary

I am trying to use Cloudinary as a CDN and am having some trouble getting file uploads to work properly. I have followed their blog posts and website, but am running into a consistent and very annoying error.
I have a model associated with both an image (a cover photo) and a media object (a PDF or ebook, like a .mobi or .epub). I have a model form set up to create an object:
class NewMediaObjectForm(forms.ModelForm):
class Meta:
model = MediaObject
fields = ('cover_photo', ...)
cover_photo = CloudinaryJsFileField(options={'tags': 'cover_photo'})
Now, I've read this tutorial from Cloudinary and I know that their form looks like this:
class NewMediaObjectForm(forms.ModelForm):
class Meta:
model = MediaObject
fields = ('cover_photo', ...)
cover_photo = CloudinaryJsFileField(options={'tags': 'cover_photo'})
Here's my problem: if I match their level of indention, the generated HTML shows that the input field is getting all of the right Cloudinary stuff attached to it - but the upload itself doesn't work. The page simply refreshes with an error message stating that no image was selected. Importantly, I can see from the generated HTML that the tags I've specified are coming through.
If I use method #1, with my indention, the file uploads to Cloudinary but none of my tags are applied. It also treats everything as an image, giving me a "invalid image file" error when trying to upload anything other than images (such as the ebook files I mentioned earlier).
I want both - how can I get this upload field to work AND get it to respect the options I'm trying to define?
(I do have cloudinary.config called in the appropriate views; I do have cloudinary_includes and cloudinary_js_config in the appropriate templates; I've imported everything and am calling cl_init_js_callbacks on the form in the view.)
One more addition - I am running this on a local machine using manage.py's runserver rather than deploying, if that has any impact on the configuration.
UPDATE:
I found something I was doing wrong. I've fixed it and made things worse.
The necessary jQuery was not being loaded. Now I am loading it, but the upload button simply doesn't function. I press the button, I select the file, the select dialog disappears, and it shows that no file has been selected. However, I can see that the tags are being passed to the generated HTML, so it's a step in the right direction. Any ideas?
Please forgive me. This was a PEBCAK issue; I will leave this visible for anyone else who may make the same mistakes I've made in the future.
Make sure the proper jQuery scripts are being loaded - open the Chrome developer console, Firebug, whatever and double check. Then, make sure they're being loaded after the DOM so that there are elements for the script to attach to.
Cloudinary will expect html/cloudinary_cors.htmlto be accessible in your static directory.
Either I have broken something, or the default behavior for this particular type of ModelField is to simply IMMEDIATELY upload the selected file and continue displaying "No File Chosen." I thought that nothing was happening and was very surprised when I saw 50+ images successfully uploaded.

How to upload images to Django media without subdirectory

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.