我按照本教程将amazon S3应用到我的django应用程序中: http://djangotricks.blogspot.com/2013/12/how-to-store-your-media-files-in-amazon.html
在其中,他定义了一个函数upload_avatar_to,它有两个参数:
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(),
)
然而,当他打电话给他时,他没有提供任何参数:
class Profile(models.Model):
# ...
avatar = models.ImageField(_("Avatar"), upload_to=upload_avatar_to, blank=True)
# ...
如果在调用时没有提供实例和文件名,该函数如何获取?
我想在函数调用中添加一个额外的参数,比如" foldername"。我怎么能这样做?
答案 0 :(得分:1)
在Django文档中有明确记录,upload_to可以是可调用的: https://docs.djangoproject.com/en/1.6/ref/models/fields/#django.db.models.FileField.upload_to
根据官方文件:
这也可以是一个可调用的函数,例如一个函数,它将被调用以获取上传路径,包括文件名。 此callable必须能够接受两个参数,并返回一个Unix风格的路径(带有正斜杠)以传递给存储系统。将传递的两个参数是:
<强>实例强>
定义FileField的模型实例。更具体地说,这是附加当前文件的特定实例。
在大多数情况下,此对象尚未保存到数据库,因此如果它使用默认的AutoField,则可能还没有其主键字段的值。 强>
<强>文件名强>
最初提供给文件的文件名。在确定最终目的地路径时,可能会或可能不会考虑这一点。
答案 1 :(得分:0)
这看起来不像函数upload_avatar_to()的调用,而是将函数本身作为参数传递,因此可以在头像中调用它。
答案 2 :(得分:0)
正在发生的事情是Django正在最后一行代码中传递函数对象 - 当时没有调用该函数。稍后将在ImageField
构造函数中调用该函数,在该构造函数中将为其提供instance
和filename
参数并返回一个值。这很容易做到,因为函数是Python中的第一类对象。
正如petkostas在他的链接中显示的那样,你提供的函数必须正好使用两个参数,实例和文件名。不过,我们可以解决这个问题!
你可以做的是为upload_avatar_to
创建一个函数包装器,它允许你提供额外的参数,同时仍然符合Django的要求。看看这个:
def upload_to_wrapper(foldername):
def wrapper(instance, filename):
upload_avatar_to(instance, filename, foldername)
return wrapper
然后你会像这样定义你的函数:
def upload_avatar_to(instance, filename, foldername):
# Do your thing.
最后,这是您要拨打的最后一行,以及您提供所需foldername
的地方:
avatar = models.ImageField(_("Avatar"), upload_to=upload_to_wrapper(foldername), blank=True)
基本上,upload_to_wrapper
会返回upload_avatar_to
对象的修改版本,该对象已提供foldername
,且只需要instance
和filename
指定。这允许您解决Django的要求。该特定ImageField
函数要求您提供一个取instance
和filename
的函数对象,但这正是upload_to_wrapper
返回的函数,因此您可以继续使用。