I can't get my FileField's url set to what I want.
My model is defined by
class MyModel(models.Model):
pdf_file = models.FileField(upload_to="reports", null=True, blank=True)
# more stuff
and I create an instance using:
myModel = MyModel()
myModel.pdf_file = "some_file.pdf"
myModel.save()
myModel.pdf_file.url returns <MEDIA_URL>/some_file.pdf, while I would expect it to be <MEDIA_URL>/reports/some_file.pdf, because of the upload_to attribute.
What am I missing?
EDIT
I first tried to set a File object instead of a string but it duplicates my file with a _<duplication_num> appended to it, so I first create my file in a tmp folder, and delete it:
myModel.pdf_file = File(open(TMP_FILE_PATH + filename))
myModel.save()
# now that the file is saved to its final location, delete tmp
filepath = os.path.abspath(TMP_FILE_PATH + filename)
os.remove(filepath)
upload_to is used for uploading, You're assigning the string name directly. upload_to takes action only when you create a FileField object (by uploading from a form).
You can read the documentation here
upload_to is a directory relative to your project root where the files you upload are meant to be stored. But you are not assigning it a file, you are assigning it a string, which seems to be causing your FileField to assume you have a file named some_file.pdf in your MEDIA_ROOT.
Repeat: assigning a filename (string) makes FileField to ignore the path defined in upload_to and takes the given string as the real path.
Good luck :)
Related
I have to create and save django model containing filefield with a downloaded attachment.
somefield = models.FileField(upload_to='somefolder/%Y/%m/%d')
I have downloaded the attachment but when I give path to the downloaded attachment as filefield upload to argument, attachment is not getting saved. I checked the folder and could not find the file.
My procedure is as follows
1.Download attachment and save it.
2.Call Model with filefield.
path='path_to_downloaded_attachment'
obj = somemodel.objects.create(param1=value, param2=value, somefield=path, param3=value)
obj.save()
Is django expecting any arguments other than path?
You can pass a lambda to upload_to:
def generate_filename(instance, filename):
return find_filename(instance, filename) # based on your rules
class yourmodel(models.Model):
somefield = models.FileField(upload_to=generate_filename)
I know that there is a very similar thread here, but I cannot find the solution to my problem.
I need to rename a file which is save in django models.FileField
I tried this
os.rename(old_path, new_path)
mod.direct_file = File(open(new_path))
mod.save()
And this
mod.direct_file.save(new_path, File(open(old_path)))
os.remove(old_path)
And many other ways, but nothing seemed to help. A new file is created in all ways, however, data in filefield does not change at all.
EDIT: SOLVED
os.rename(old_path, new_path)
cursor = connection.cursor()
cursor.execute("UPDATE mods_mod SET direct_file = %s WHERE id = %s", [new_name, mod.id])
transaction.commit_unless_managed()
I don't think you need to use raw SQL for this. I think you need to rename the file using the os facility, then set the model's FileField name to the new name. Maybe something like:
os.rename(model.direct_file.path, new_path)
model.direct_file.name = new_name
model.save()
new_name = 'photos_preview/' + str(uuid.uuid1())
os.rename(photo.image_preview.path, settings.MEDIA_ROOT + new_name)
photo.image_preview.name = new_name
photo.save()
The current Django documentation states:
"When you access a FileField on a model, you are given an instance of FieldFile as a proxy for accessing the underlying file." See docs for further reading.
Instead of using the Python File object to open the file, you should use FieldFile.open() to open the file, then manipulate the file's path accordingly. Afterward, save the model object, and the changes to the path should persist.
I came across this issue when I had blobs saved into django with no file extension, and I wanted to correct that. Best used when looping over a filtered queryset.
You cannot change instance.picture.path, and trying to access instance.picture.file.* will give an error because accessing it will try to open the old file. Setting instance.picture.name will still not let you access instance.picture.file.*, even after saving.
You can simply set the ImageField object itself to the location and all will work:
(Tested with django 1.10)
import imghdr
import os
from django.db import models
class MyModel(models.Model):
picture = models.ImageField()
instance = MyModel.objects.first()
if os.path.exists(instance.picture.path):
extension = imghdr.what(instance.picture.path)
os.rename(instance.picture.path, instance.picture.path + '.' + extension)
instance.picture = instance.picture.name + '.' + extension
instance.save()
You may use the following:
Suppose 'obj' is the django object that you want to rename. Then do this:
obj.file_field_name.name = new_name
obj.save()
It seems changing filename of a binary in FileField is pretty unflexible according to the django docs. It contains the path from Media root.
That points out to a name attr that is reflecting the path, not just the filename itself. Docs: This is the way that django model can find the file
I have made something to overwrite a file already uploaded with :
class OverwriteStorage(FileSystemStorage):
def get_available_name(self, name):
if self.exists(name):
os.remove(os.path.join(settings.MEDIA_ROOT, name))
return name
But my file is in a model :
class Work (models.Model):
file = models.FileField(storage=OverwriteStorage(), upload_to=path)
group = models.ForeignKey(Group, related_name='work_list')
And the new upload makes a new enter, so I have :
A model without file (that bug when I ask file.size..)
My new model
How can I remove my model when my file is deleted?
I have tried to change again FileSystemStorage process but I can't use any argument (said in doc and tested for hours ;)), I have tried to change save process too, but I didn't succeed..
A few things to check before continuing to troubleshoot:
Have you set the MEDIA_ROOT and MEDIA_URL in the settings.py file?
Check this link for more info on Managing files
I would take advantage of Django's built-in file storage rather than building something from scratch
My solution :
for work in groupwork : #It is the list of work associate with my group
try :
path = work.file.path.lstrip(SITE_ROOT+'/'+MEDIA_ROOT+'/').rstrip(request.FILES['file'].name)
deletedwork = groupwork.get(file=path+request.FILES['file'].name)
deletedwork.delete()
except:
pass
i would like to dynamically set the file storage path from the view regardless of the actual media_root path. is this possible. i have looked into custom storage objects and i am aware of the custom upload_to method call. currently i have a method that is called when my ImageField model upload_to is specified. this lets me change the directory within media_root. i have tried to do something similar with an overriden FileSystemStorage class but whatever it is set to i think it is bound before i can modify it within a view. if fileupload handler is the way to go i would be curious as to how to implement one.
If path that you specified in upload_to starts with / then it will be considered as absolute path. Through this you can set any path that you want regardless of MEDIA_ROOT.
you can do this in your view path = default_storage.save(filePath, ContentFile(file))
where filePath is file path where you need to store, and file is the file which is uploaded by user. this function will return you the path by storing file.
file = request.FILES['filee']
filePath = '%s/%s' % ('path/to/directory', file.name)
file = file.read()
path = default_storage.save(filePath, ContentFile(file))
I need to generate name of uploaded image with mask
images/{{ uploaded_image.id }}.jpg
I think the best way to do this is FileField.upload_to property, but it is written Here:
In most cases, this object will not have been saved to the database yet, so if it uses the default AutoField, it might not yet have a value for its primary key field.
May be in my case it will be better to rename file after saving object in save() method?
What I do is give upload_to a function, then assign a UUID is the function for it to save to:
import uuid
def get_upload_to(instance, filename):
instance.uuid = uuid.uuid4().hex
return 'blah/%s/%s' % (instance.uuid, filename)
class Photo(models.Model):
file = models.FileField(max_length=200,upload_to=get_upload_to)
uuid = models.CharField(max_length=32)
To avoid concurrency issues, you will need to store your object to the database before you determine the filename (because even if you get the next incremental id, which is possible, it may change while you save the file.) So store the object and then rename the file.
Thanks, Blixt and Todd! I choose better solution for my issue:
import time
class Image(models.Model):
def _get_upload_to(instance, filename):
return 'images/%f.jpg' % time.time()
original = models.ImageField(upload_to=_get_upload_to, ....)
It is guarantees that every filename will be unique in the same directory. In my case I need only jpg files, so in other cases it possible to substitute original extension