【问题标题】:Preferred pythonic way to associate upload_to function with model class?将upload_to函数与模型类相关联的首选pythonic方式?
【发布时间】:2012-10-01 14:07:04
【问题描述】:

我有一个带有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 类相关的函数来污染模块范围。

在第二种方法中,我使用可调用类模式将函数与 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 装饰器的建议(c.f. https://stackoverflow.com/a/9264153/790075),但我发现当我这样做时,函数永远不会执行并且文件名最终看起来像:/path/to/file/&lt;classmethod object&gt;,与文件路径中嵌入的方法对象,这当然不是故意的!

以下哪一个是首选模式?有没有更好的办法?

【问题讨论】:

  • 顺便说一句,您可以避免完全定义函数/方法/类,并将您的 get_car_photo_file_path 转换为 ImageField 调用中的内联 lambda。但这可能完全不可读。

标签: python django django-models


【解决方案1】:

我建议你:

import this

对我来说,这属于 Zen of Python 的部分说明:

Simple is better than complex.
Complex is better than complicated.

我认为您的简单解决方案更好。但是,您的情结并不过分复杂。我想你可能会没事的。只是我的两分钱。

【讨论】:

  • 我希望得到更具体的东西,但我不能说我不同意你的观点!
  • 对不起。我试图非常具体,并说我认为简单的解决方案(第一个)更好。之所以如此,是因为我认为它更贴近“Python之禅”。但是,使用 Callable 的解决方案并不可怕。我只是更喜欢第一个。
【解决方案2】:

有一个命名约定可以防止名称污染。

  • 使用_get_car_photo_file_path 将您的函数标记为内部函数(虽然没有隐藏);
  • 在课堂外使用__get_car_photo_file_pathto prevent access

您可以在CarPhoto 类中添加这样的类方法或静态方法,这比添加可调用类更简单(后者让我想起Java 为一种方法而定义匿名类的方式)。

名称将清楚地表明_get_car_photo_file_path 是一个实现细节,而不是接口的一部分,从而防止污染类的命名空间。作为CarPhoto的方法,该函数不会污染模块的命名空间。

【讨论】:

  • 确实如此,但您建议我如何将其用于上述任何一种情况?
  • 不幸的是,这种方法失败了。请参阅我对@vartec 建议的回复。
【解决方案3】:

目前在我正在使用的代码中,我们有最简单的代码的变体。唯一的区别是,由于该函数是供内部使用的,所以它带有_前缀。

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) 

【讨论】:

  • 第二个建议是我首先尝试的,但这失败了,因为您在这里无权访问CarPhoto(类)或self。见 cmetsstackoverflow.com/a/3091717/790075
  • @turtemonvh:静态方法不需要self
  • @turtemonvh:我看不到您如何在计算文件路径的函数中使用类的selfinstance 参数从未在您帖子中的函数中使用。
  • @vartec 是的,但它确实需要类,它也不可用
  • @9000 没错:我没有在函数中使用self。文件名是作为 uuid 生成的,不是基于文件本身的任何属性派生的。我的意思不是我需要self 来完成该功能的工作,而是调用staticmethodclassmethod 需要访问selfself.__class,两者都不可用。
猜你喜欢
  • 1970-01-01
  • 2011-02-19
  • 2021-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多