Django: Saving a file from disk with FileField - django

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.

Related

FileField: force using TemporaryUploadedFile

When uploading a file for a field such as this one:
file = FileField(upload_to='/path/')
Django uses either an InMemoryUploadedFile or a TemporaryUploadedFile. The latter is stored on the disk and its file name can be accessed with the temporary_file_path property. The storage choice depends on the file size.
How can I override this behaviour and always upload as a TemporaryUploadedFile for this model field?
The reason I am asking this is because I need to write a validator that uses an external library that can only take file paths as input, no data streams.
By default the upload handlers are:
[
'django.core.files.uploadhandler.MemoryFileUploadHandler',
'django.core.files.uploadhandler.TemporaryFileUploadHandler',
]
And files smaller than 2.5MB are handled with MemoryFileUploadHandler.
So just say in your settings:
FILE_UPLOAD_HANDLERS = ['django.core.files.uploadhandler.TemporaryFileUploadHandler',]

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.

Django FileField upload

I am quite confused.
I have wrote an upload form in my site. everything works perfectly..
however, I am reading that I needed to implement a function like handle_uploaded_file to dump the file content from the request.FILES to a physical file.
however , I didn't do it any the file exists in the location I set the upload_to in the FileField field. everything works as expected..
Am I missing something ? why do I need handle_uploaded_file then ?
No, you do not need to do a handle_uploaded_file.
When you save the object (form.save) Django already does this for you.
Look this:
https://github.com/django/django/blob/master/django/db/models/fields/files.py#L270-276

Django save file

I want to create thumbnails for uploaded images. I know there are some libraries available, but I have very basic needs and I would prefer to do this on my own.
My model goes like this:
from image_tools import resize
class Photo(models.Model):
# some fields
image = models.ImageField(
upload_to='images',
height_field='height',
width_field='width'
)
thumb = models.ImageField(
upload_to='thumbs',
editable=False
)
def save(self):
self.thumb = self.image
resize(self.image.path, self.thumb.path, 50, 40)
super(Photo, self).save()
Here resize() is a simple function I have written which accepts as arguments the original file path and the destination path and the dimensions and stores a thumbnail. The only problem is that the file is not yet on the disk at this moment.
Is there a way to force saving the file itself on its location, so that it will be available to my function?
Please, feel free to suggest better ways to handle this matter. Still I would like to know how to handle files which are not yet saved, whatever the best solution turns out to be.
There are a few ways to do this. One you have the raw image data, you can write it to a file pretty easily (look up django file uploading to see how to save an uploaded file to disk). You can read any file your django process (or apache) has access to, not just in the path of your django instance.
Another thing you can do before saving this is to use PIL to thumbnail the image and save it:
http://effbot.org/imagingbook/image.htm
You can also upload the data to s3 using boto s3, if you want the images hosted on a CDN.
Storing the file directly is not a good idea because you ignore the default file storage (i.e. file system, amazon s3, ...)
Better approach is to use django File class
from django.core.files import File
# Create a Python file object using open() and the with statement
>>> with open('/tmp/hello.world', 'w') as f:
... myfile = File(f)
... myfile.write('Hello World')
Also to delete the file use the default storage class
See link below for more details
https://docs.djangoproject.com/en/1.5/topics/files/

Save FileField file uploads someplace other than MEDIA_ROOT?

Can I use FileField to handle a file, but store it someplace not under MEDIA_ROOT/MEDIA_URL but somewhere else entirely.
Seeking is to ensure it is not downloadable; although denying read permissions would do the trick here's hoping for something better... like a different directory altogether.
There are a few ways to do this.
First, you can take a look at handling uploaded files from the Django docs. If you read it over, basically you can handle the upload of the file within your view in the same part where you are processing your form.
Another option, and one which I think would be better is to use a custom file storage system. You could do this very simply using the existing one as a base but simply change the location, then use it as an argument in your FileField. For example:
from django.core.files.storage import FileSystemStorage
my_store = FileSystemStorage(location='/some/other/dir')
class SomeModel(models.Model):
file = models.FileField(storage=my_store)
Hope that helps!
Considering that the only actual use of MEDIA_ROOT in all of Django is to determine where uploaded files are stored, seems like it would make more sense to just point MEDIA_ROOT where you want your uploaded files, and then use a different setting for the path to your static assets. This is the approach taken by Pinax and django-staticfiles, which use STATIC_URL and STATIC_ROOT settings.
Note that even the documentation page on serving static assets in development no longer recommends using MEDIA_ROOT for that purpose, it demonstrates using your own STATIC_DOC_ROOT setting.