我有一个Django ImageField的课程,我一直在努力决定存储该字段的upload_to
功能的两种选择。第一种方法非常简单。该函数在模块级别定义(c.f。https://stackoverflow.com/a/1190866/790075,https://stackoverflow.com/a/3091864/790075):
def get_car_photo_file_path(instance, filename):
ext = filename.split('.')[-1]
filename = "%s.%s" % (uuid.uuid4(), ext) # chance of collision <1e-50
return os.path.join('uploads/cars/photos', filename)
class CarPhoto(models.Model):
photo = models.ImageField(upload_to=get_car_photo_file_path)
这很简单易懂,但通过添加一个实际上仅与CarPhoto类相关的函数来污染模块范围。
在第二种方法中,我使用callable-class模式将函数与CarPhoto类更紧密地关联起来。这会将upload_to
函数移出模块范围,但感觉不必要的复杂。
class CarPhoto(models.Model):
class getCarPhotoFilePath():
# Either use this pattern or associate function with module instead of this class
def __call__(self, instance, filename):
ext = filename.split('.')[-1]
filename = "%s.%s" % (uuid.uuid4(), ext) # chance of collision <1e-50
return os.path.join('uploads/cars/photos', filename)
photo = models.ImageField(upload_to=getCarPhotoFilePath())
我已经看到了使用@staticmethod
和@classmethod
装饰器(cf https://stackoverflow.com/a/9264153/790075)的建议,但我发现当我这样做时,函数永远不会执行,文件名最终看起来像:/path/to/file/<classmethod object>
,方法对象嵌入在文件路径中,这当然不是意图!
其中哪一种是首选模式?还有更好的方法吗?
答案 0 :(得分:1)
我建议你:
import this
对我来说,这属于Zen of Python部分的陈述:
Simple is better than complex.
Complex is better than complicated.
我认为你的简单解决方案更好。但是,你的情结不会感到过于复杂。我想你可能都会好起来的。只是我的两分钱。
答案 1 :(得分:0)
有一个命名惯例可以防止名称污染。
_get_car_photo_file_path
将您的功能标记为内部(虽然未隐藏); __get_car_photo_file_path
to prevent access。你可以将这样的classmethod或static方法添加到你的CarPhoto
类中,这比添加一个可调用类更简单(后者让我想起了Java为一种方法定义一个匿名类的方法)。
该名称将清楚地显示_get_car_photo_file_path
是一个实现细节而不是接口的一部分,从而防止污染类的命名空间。作为CarPhoto
的方法,该函数不会污染模块的命名空间。
答案 2 :(得分:0)
目前在我正在使用的代码中,我们有最简单的变体。唯一的区别是,由于该函数仅供内部使用,因此使用_
前缀对其进行标记。
def _get_car_photo_file_path(instance, filename):
[...]
class CarPhoto(models.Model):
photo = models.ImageField(upload_to=_get_car_photo_file_path)
但是,我确实认为这会更像Pythonic(或更多的OOP):
class CarPhoto(models.Model):
@staticmethod
def _get_file_path(instance, filename):
[...]
photo = models.ImageField(upload_to=_get_file_path)