I want to customize the folders that are used to save my images for a record...currently, I have:
original_image = models.ImageField(upload_to='photos')
But what I want to have is the images being saved to photos/<vehicle's_stock_number>/...how can I add the stock number to the end of the upload path?
Per the documentation for FileField.upload_to:
This may also be a callable, such as a function, which will be called to obtain the upload path, including the filename. This callable must be able to accept two arguments, and return a Unix-style path (with forward slashes) to be passed along to the storage system. The two arguments that will be passed are:
instance: An instance of the model where the FileField is defined. More specifically, this is the particular instance where the current file is being attached. 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.
filename: The filename that was originally given to the file. This may or may not be taken into account when determining the final destination path.
So if you've got a model which has a stock_number attribute, you could use something like this:
def get_path(instance, filename):
return 'photos/%s/%s' % (instance.stock_number, filename)
Related
In my django app I create a string which I have to save to my database as a File.
If i understand correctly, django is supposed to automatically upload the file when I save the entry:
class Foo(models.Model):
bar1=models.ForeignKey(Table1)
bar2=models.ForeignKey(Table2)
res=models.FileField(upload_to='MYPATH')
The problem is that to create an instance of Foo, I have to first create a physical file on the server's disk which would mean two copies would be created (one by me in order to create a database entry, one by django when saving the entry).
As far as I can see, I must create the file myself in 'MYPATH' and instead of using a FileField, I have to save a reference in the database (essentially what django is doing ????). However I have doubts that this is the best method as
It doesn't strike me as Pythonesque.
I won't have access to the same methods as when using a real FileField. For instance when calling it, I won't have a FieldFile but just a reference string.
Basically, what I wanted to do was: String --> ContentFile (or some form of "virtual" file) --> Physical File handled by Django when saving entry in the database.
entry = Foo(bar1=var1, bar2=var2, res=ContentFile(XMLSTRING))
entry.save()
This doesn't work, but it shows what I want to achieve.
So, please show me one of the following three:
How to save a file to the database without physically creating it (using a ContentFile doesn't create a physical file after saving the entry which is what I want to do)
Make django not upload the given file but use the already uploaded version whilst maintaining all the methods provided by FileField
What I don't understand.
I apologize for [my english, my lack of understanding, the lack of clarity]
Anything you need to know, I'd happy to specify.
EDIT: I looked at this thread, but there, the urlretrieve creates a temp file, which is something I don't really want to do. Maybe I should be doing that, but is there a better way?
How can I detect that the name of a file that a user has provided for upload (via a django.forms.ModelForm using a FileField field) is a duplicate of one that exists, and thus decide to fail validation on the form?
I'm finding this particularly challenging, because from within the form, I don't see how I can find out what the value of upload_to is for this FileField, so I can't go looking myself in the file system to see if that file is there already.
As i see it you have 2 options:
Set a value in your settings.py to hold your 'upload_to' and then use it to check when you are validating.
Something like this to verify would work (you need to change your upload_to ofc):
from django.conf import settings
if settings.UPLOAD_TO:
# Do something
Issue with that is that you can't have subfolders or anything complex there.
A second option would be, as mentioned in your comments, to add a new column to your model that holds a hash for your file. This approach should work better. As someone mentioned in your comments, to avoid uploading a big file, checking, failing, uploading another big file, etc, you can try to hash it in the client and verify it via ajax first (you will verify it again in the server, but this can make things go faster for your users).
Older question, but Django 1.11 now supports the unique option on FileField. Set unique=True on your field declaration on your model.
It shouldn't matter what you are setting upload_to to. The file name will still be stored in the database.
Changed in Django 1.11:
In older versions, unique=True can’t be used on FileField.
https://docs.djangoproject.com/en/1.11/ref/models/fields/#unique
FilePathField is described in Django's doc as:
A CharField whose choices are limited to the filenames in a certain directory on the filesystem.
Then I assume it checks if the existence of the file. But actually it doesn't:
class Unit(models.Model):
path = FilePathField(path="/home/jason/")
In IPython shell:
unit = Unit(path="non_exist_file_name")
unit.save()
No exception raised. So I have to check os.path.isfile myself or I am not using FilePathField correctly for my need (restrict only to existing files when creating a Unit)?
If I'm not mistaken, the validation for the FilePathField is not run if you don't go trough a Form. Try to call unit.clean_fields() before saving.
I'm attempting to detect changes to an ImageField in order to programatically sync the changes with Hg. The model containing the ImageField is being localized using Django-multilingual, so I have to detect changes for each field individually rather than just assume the file changed every time.
I am using pre and post save signals to accomplish this, saving the instance in the pre-save and detecting the changes in the field values in the post-save. This works great for when images are added, removed, or changed with an image of a different filename. However, when I upload an image of the same filename, my code is unable to detect that the image actually changed so no file changes get synced with Hg.
I want to be able to generate a checksum for the old file (easily done as I know where it lives from the presave instance), and compare this to a checksum of the new file (not as easy, as trying to pull it in from the field value takes me to the old file).
If there is a way for me to find the newly uploaded file (presumably in memory as Django doesn't temp save files under 2.5MB), and save it to a temporary directory, it would be easy for me to generate a checksum for it. However, I am not sure where I would get the file from.
Where could I get the file from during a post_save signal? Or is there another method of accomplishing this change detection that I haven't thought of?
Thanks,
Rich
Add this snippet"
def has_changed(instance, field):
if not instance.pk:
return False
old_value = instance.__class__._default_manager.\
filter(pk=instance.pk).values(field).get()[field]
return not getattr(instance, field) == old_value
then in your save
def save(self, *args, **kwargs):
if has_changed(self, 'field_here'):
super(Sneetch, self).save(*args, **kwargs)
So here is my situation. I have a model that I am saving, and it contains the following file:
file = models.FileField(storage=s3store, upload_to=custom_upload_to)
S3Store is a custom storage solution that I have implemented. Within that custom storage solution, I have a dictionary to all my different Amazon S3 Buckets [a dictionary with all S3BotoStorage connections]. Depending on who is uploading the file, I need to send it to it's appropriate S3BotoStorage, that is set to the appropriate bucket. I was wondering if it was possible to pass a parameter to my s3store.save() method from within my model save method?
I thought about simply appending the bucket_name to the filename, but appending & then removing would take too much calculation time no? (and memory).
Hope it makes sense!