将upload_to函数与模型类相关联的首选pythonic方法?

时间:2012-10-01 14:07:04

标签: python django django-models

我有一个Django ImageField的课程,我一直在努力决定存储该字段的upload_to功能的两种选择。第一种方法非常简单。该函数在模块级别定义(c.f。https://stackoverflow.com/a/1190866/790075https://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>,方法对象嵌入在文件路径中,这当然不是意图!

其中哪一种是首选模式?还有更好的方法吗?

3 个答案:

答案 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)