Question

I have the following model.

class Image(models.Model):
    customer = models.ForeignKey(Customer, related_name='images')
    image = models.ImageField(upload_to='/pictures/', verbose_name='Image')

Each time user add a new Image I want it to go under pictures/customer.id/custom_filename When I was using local filesystem, that was easy. I used a function that handled file chunks upload with a new name and returned the new path. But now I want to use S3 to store my files. So I am using django-storages. I did the following tests:

testmodel

class TestModel(models.Model):
    name = models.CharField(max_length=10)
    logo = models.ImageField(upload_to='pictures/')

when I do this in my view

def index(request):
    form = TestModelForm(request.POST or None, request.FILES or None)
    if request.method == 'POST':
    if form.is_valid():
        print 'posting form'
        model = form.save(commit=False)
        print model.name
        print model.logo.url
        model.save()

and the image is uploaded as it should under mybucket.s3.amazon.com/pictures/logoname.jpg But if I change the file name by some way like

def index(request):
    form = TestModelForm(request.POST or None, request.FILES or None)
    if request.method == 'POST':
    if form.is_valid():
        print 'posting form'
        model = form.save(commit=False)
        print model.name
        filename = str(request.FILES['logo']).split('.')[0]
        extension = str(request.FILES['logo']).split('.')[1]
        path = '%d%d%d_%s_%d.%s' %(datetime.now().year, datetime.now().month, datetime.now().day, filename, models_no+1, extension)
        model.logo = path
        print model.logo.url
        model.save()

i get a new url which is mybucket.s3.amazon.com/newlogoname.jpg (correct since I didn't user pictures in the new path) but the file is not uploaded. Must I do it manually using boto? I guess it's the only way since folders for each customer (initial example) might not exist and need to be created. What is the correct way to upload images at custom locations/directories for each model?

I tried to call default storage directly to save the image in the location I wanted but didn't work

default_storage.save('pictures/one.jpg', ContentFile(request.FILES['logo']))

The key is created (the folder and the file) but the image is empty. I think using cloud storage in a flexible way is very difficult :(

Was it helpful?

Solution

You can pass a callable as the upload_to named argument, in your model definition (so you actually don't have to do this on the view level). To make it clear, try doing something like this:

class Image(models.Model):
    customer = models.ForeignKey(Customer, related_name='images')
    image = models.ImageField(upload_to=self.generate_upload_path, verbose_name='Image')

    def generate_upload_path(self, filename):
        return os.path.join('/pictures/'+str(self.customer.id), filename)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top