我有一个抽象模型类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
答案 0 :(得分:5)
鉴于评估时
,错误很自然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
但这并不能解决你所有的问题。在get_directory
类中添加(或覆盖)方法Video
不会更改模型的upload_to
属性的file
属性。
更新
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'
答案 1 :(得分:1)
如果你需要使用基类属性作为子类的一部分,这可以通过一些调整以类似的方式完成:
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
等于:
files
UploadItem
{li> files/videos
Video
可能对需要共享一些公共基本属性的更复杂对象有用。