【问题标题】:passing a callback as upload_to to FileField将回调作为 upload_to 传递给 FileField
【发布时间】:2010-09-08 16:24:20
【问题描述】:

我有一个用于处理上传文件的抽象模型类 UploadItem。我希望每个子类都能够定义 upload_to 路径。为此,我将回调传递给 FileField 的构造函数。

这是一个例子:

class UploadItem(models.Model):
    file = models.FileField(upload_to=UploadItem.get_directory) 


    class Meta:
        abstract = True
# I want videos to be storred in 'videos/' directory
class Video(UploadItem):
    def get_directory(self, instance, filename):
        return 'videos/'

但这不起作用,我收到此错误:

file = models.FileField(upload_to=UploadItem.get_directory) 
NameError: name 'UploadItem' is not defined

【问题讨论】:

    标签: django directory filefield


    【解决方案1】:

    考虑到在评估时,错误是自然的

    file = models.FileField(upload_to=UploadItem.get_directory) 
    

    UploadItem 类尚未定义。您可以执行以下操作以使其正常工作:

    def get_directory():
        pass
    
    class UploadItem(models.Model):
        file = models.FileField(upload_to=get_directory)
    
        class Meta:
            abstract = True
    

    但这并不能解决您的所有问题。在Video 类中添加(或覆盖)方法get_directory 不会更改模型的file 属性的upload_to 属性。

    更新

    documentation 表示upload_to 可以是可调用的。

    这也可能是一个callable,比如一个函数,会被调用来获取上传路径,包括文件名。此可调用对象必须能够接受两个参数,并返回要传递给存储系统的 Unix 样式路径(带有正斜杠)。

    鉴于此,我们可以编写一个自定义回调函数,如下所示:

    categories_and_paths = { 'video': 'videos/', 'photo': 'photos/' } # etc.
    def get_directory(instance, filename):
        category = instance.category
        return categories_and_paths.get(category, '')
    

    Instance 这里将是相应模型的实例。为此,每个模型实例都应该有一个类别字段。我们可以在模型主体中添加一个。

    class Video(UploadItem):
        category = 'video'
    

    【讨论】:

    • 那么你有什么建议来实现我想做的事情?我希望每个子类重新定义上传文件的位置。谢谢
    • 我明白了,我希望回调成为课程的一部分。但这是不可能的。我会这样做。
    【解决方案2】:

    如果您需要使用基类属性作为子类的一部分,这可以通过一些调整以类似的方式完成:

    import os
    
    # ...
    
    def get_directory(instance, filename):
        return instance.get_file_directory(filename)
    
    
    class UploadItem(models.Model):
        FILE_DIRECTORY = 'files/'
    
        file = models.FileField(upload_to=get_directory) 
    
        class Meta:
            abstract = True
    
        @staticmethod
        def get_file_directory(filename):
            return os.path.join(UploadItem.FILE_DIRECTORY, filename)
    

    然后在子类中:

    class Video(UploadItem):
        FILE_DIRECTORY = 'videos/'
    
        def get_file_directory(self, filename):
            filename = os.path.join(self.FILE_DIRECTORY, filename)
            return super().get_document_path(filename)
    

    这样你将有upload_to等于:

    • filesUploadItem
    • files/videosVideo

    对于需要共享一些公共基础属性的更复杂的对象可能很有用。

    【讨论】:

      猜你喜欢
      • 2012-02-23
      • 2018-11-08
      • 1970-01-01
      • 2016-10-08
      • 1970-01-01
      • 1970-01-01
      • 2014-11-08
      • 2012-01-15
      • 1970-01-01
      相关资源
      最近更新 更多