How does this python function get its parameters?

I am implementing amazon S3 in my django app by following this tutorial: http://djangotricks.blogspot.com/2013/12/how-to-store-your-media-files-in-amazon.html

In it, it defines the upload_avatar_to function, which takes two parameters:

def upload_avatar_to(instance, filename):
    import os
    from django.utils.timezone import now
    filename_base, filename_ext = os.path.splitext(filename)
    return 'profiles/%s%s' % (
        now().strftime("%Y%m%d%H%M%S"),
        filename_ext.lower(),
    )

      

However, when it calls it, it doesn't provide any parameters:

class Profile(models.Model):
    # ...
    avatar = models.ImageField(_("Avatar"), upload_to=upload_avatar_to, blank=True)
    # ...

      

How does the function get the instance and filename if it was not dispatched when called?

I want to add an extra parameter to the function call, like "folder name". How can i do this?

+3


source to share


3 answers


It's clearly documented in the Django documentation, upload_to can be callable: https://docs.djangoproject.com/en/1.6/ref/models/fields/#django.db.models.FileField.upload_to

According to the official documentation:

It can also be called, for example, a function that will be called to get the download path, including the filename. This callee must be able to take two arguments and return a Unix-style path (with a forward slash) to be passed along with the storage system. The two arguments to be passed are as follows:



Instance The
instance of the model in which the FileField is defined. More specifically, it is the specific instance into which the current file is inserted.

In most cases, this object has not yet been saved to the database, so if it uses the default AutoField, it may not yet have a value for its primary key field.

filename
The name of the file that was originally supplied to the file. This may or may not be taken into account when determining the final destination path.

+1


source


This is not like calling the upload_avatar_to () function, but rather passing the function itself as a parameter so that it can be called inside the avatar.



0


source


What happens is that Django is passed the actual function object in the last line of code - the function is not called at this time. This function will later be called inside the constructor ImageField

, where it will be given arguments instance

and filename

and return a value. This is easy to do because functions are first-class objects in Python.

As petkostas showed in its link, the function you provide must take exactly two arguments, an instance and a filename. We can get around this though!

What you can do is create a wrapper for a function upload_avatar_to

that will allow you to provide an additional parameter that still meets Django's requirements. Check it:

def upload_to_wrapper(foldername):
  def wrapper(instance, filename):
    upload_avatar_to(instance, filename, foldername)
  return wrapper

      

Then you define your function like this:

def upload_avatar_to(instance, filename, foldername):
  # Do your thing.

      

And finally, this is the last line you would call and the point at which you indicate foldername

which one you want:

avatar = models.ImageField(_("Avatar"), upload_to=upload_to_wrapper(foldername), blank=True)

      

Essentially, it upload_to_wrapper

returns a modified version of the object upload_avatar_to

that already has foldername

, and only instance

and should be specified filename

. This allows you to work with Django requirements. This function ImageField

requires you to specify a function object that takes values instance

and filename

, but exactly what it returns upload_to_wrapper

, so you're good to go.

0


source







All Articles