Fox
Fox

Reputation: 326

Django ImageField upload_to custom path based on custom function

I am trying to set upload paths in Django ImageField with the upload_to attribute with similar to below.

Model

image = models.ImageField(upload_to=image_upload_location(image="logo"))

Function

def image_upload_location(filename, instance, *args, **kwargs):

  if image:
    defaultFolder = "images/default"
    logoFolder = "images/logo"
    generalFolder = "images/general"
    productsFolder = "images/products"
    if image == "logo":
      folder = logoFolder
    elif image == "general":
      folder = generalFolder
    elif image == "products":
      folder = "productsFolder"
    else:
      folder = defaultFolder

    return "%s/%s" % (folder, filename)

I get the following error:

TypeError: image_upload_location() missing 2 required positional arguments: 'filename' and 'instance'

I've tried to pass instance and filename but can't work out how to make this work. Any ideas on how to make this work so that I can use the same function for ImageField as I'm trying to follow the DRY principal by making a function to handle all the "set" locations.

I also don't want the date fields that Django adds.

[edit] The main thing I need to know here is how to pass the required variable "instance and filename" plus an additional variable "image" to the function from the model ImageField. :-)

Upvotes: 0

Views: 4362

Answers (1)

Dakusan
Dakusan

Reputation: 6691

You have both filename and instance as parameters of your function, which you are not passing. I recommend doing this instead, if they aren't required.

def image_upload_location(*args, **kwargs):
    filename=kwargs.pop('filename', 'DEFAULT')
    instance=kwargs.pop('instance', 'DEFAULT')

or give them defaults

def image_upload_location(filename='DEFAULT', instance='DEFAULT', *args, **kwargs):

[edit]

Also, you never instance/grab/set "Image" in your function. Either set it as a parameter, or pop it from kwargs.

[edit on 2016-01-15] - This is what I think you want.


image = models.ImageField(upload_to=image_upload_location(image_type='logo', filename='filename.jpg'))

or

image = models.ImageField(upload_to=image_upload_location(filename='filename.jpg'))

or

image = models.ImageField(upload_to=image_upload_location('filename.jpg', 'logo'))

See below for all the different combination examples


def image_upload_location(filename, image_type='', *args, **kwargs):
    if image_type=='logo':
        folder = 'images/logo'
    elif image_type=='general':
        folder = 'images/general'
    elif image_type=='products':
          folder = 'images/products'
    else:
          folder = 'images/default'

    return '%s/%s' % (folder, filename)

#All of the different ways to call it
print(image_upload_location('test.jpg')); #1 indexed argument, 1 default argument
print(image_upload_location('test2.jpg', 'logo')); #2 indexed arguments
print(image_upload_location('test3.jpg', image_type='logo')); #1 indexed argument, 1 named argument (indexed arguments can't come after named arguments)
print(image_upload_location(image_type='general', filename='test4.jpg')); #2 named arguments
print(image_upload_location(filename='test5.jpg', image_type='products')); #2 named arguments in a different order

Also, you don't need to include args and kwargs as parameters if you aren't using them.

Upvotes: 1

Related Questions