【问题标题】:When should you use @property in a model class? [duplicate]什么时候应该在模型类中使用@property? [复制]
【发布时间】:2020-04-29 02:12:45
【问题描述】:

阅读docs 时,几乎没有关于如何以及为什么在课堂上使用@property 的信息。我只能找到:

也称为“托管属性”,是 Python 2.2 版以来的一项功能。这是实现属性的一种巧妙方法,其用法类似于属性访问,但其实现使用方法调用。

当我在像 def get_absolute_url(self): 这样的模型中有一个函数时,我应该用 @property 装饰它吗?

@property
def get_absolute_url(self):
    pass

未装饰的def 和装饰有@property 的有什么区别?什么时候该用,什么时候不用?

【问题讨论】:

标签: django django-models


【解决方案1】:

什么时候应该在模型类中使用@property?

当您的类属性由类中的其他属性形成时,您应该使用@property,并且您希望它在源属性更改时得到更新。

不带@property 的示例

class Coordinates():
    def __init__(self, x, y):
        self.x = 'x'
        self.y = 'y'
        self.coordinates = [self.x, self.y]

    def revers_coordinates(self):
        return [self.y, self.x]

>>> a = Coordinates('x', 'y')
>>> a.coordinates
['x', 'y']
>>> a.revers_coordinates()
['y', 'x']
>>> a.x = 'z'
>>> a.coordinates 
['x', 'y'] # <===== no changes in a.x
>>> a.revers_coordinates()
['y', 'z']

如您所见,revers_coordinates() 做出了反应,而self.coordinates 没有。如果你想让它做出反应,@property 是一个选项。

当然你可以在函数def coordinates(self)上更改self.coordinates,但是当它被调用为没有()的属性时,这会破坏你代码中的所有地方(也许你的代码是开源的,它不仅会破坏为你)。在这种情况下,@property 就是您想要的。

@property 示例

class CoordinatesP():
    def __init__(self, x, y):
        self.x = 'x'
        self.y = 'y'
    
    @property
    def coordinates(self):
        return [self.x, self.y]

    def revers_coordinates(self):
        return [self.y, self.x]

>>> a = CoordinatesP('x', 'y')
>>> a.coordinates
['x', 'y']
>>> a.revers_coordinates()
['y', 'x']
>>> a.x = 'z'
>>> a.coordinates
['z', 'y'] # <===== a.x has changed
>>> a.revers_coordinates()
['y', 'z']

【讨论】:

    【解决方案2】:

    不同之处在于,用@property 修饰的方法的行为类似于类属性。所以你可以不使用括号直接调用它(因此没有参数。所以如果你的函数带参数你不能真正使用@property装饰器)

    对我来说,在模型中使用@property 最有用的场景是使用模板。如果您在模板中有模型对象的实例,则可以将其称为属性,但不能称为函数(您必须编写自定义模板标签)。例如,如果你有一个名为total_entries 的模型用户属性,你可以在{{ user_instance.total_entries }} 之类的模板中调用它来访问它,而不是编写模板标签。

    实际上,如果该方法没有参数,您可以将方法作为模板中的属性调用。

    另一种情况:假设您有一个使用模型字段计算布尔值的操作。例如,对于用户模型,您可能希望根据他当前的分数和会员年数来计算用户是否是“心爱的用户”。在这种情况下,使用属性装饰器更合适,因为它看起来非常清晰的语法。 (因此您将在视图中使用user.is_beloved

    【讨论】:

    • 这很有帮助,但我可以调用{{ obj.get_absolute_url}} 而不需要属性装饰器?
    • 它的行为是这样的,因为它是 django 的内置模型方法。这就是开发人员实现它的方式。
    • 但是在源代码中没有@property装饰器...
    • 好的,我刚刚检查过,结果是,如果您的方法没有参数,您可以直接在模板中调用它们,而无需在模型中使它们成为属性。 (这可能是 django 模板引擎的一个特性)。所以大多数时候,出于可读性和简单性的原因,您应该坚持使用属性装饰器。另请查看@weAreStarDust 的答案。
    【解决方案3】:

    当您使用@propertydecorator 时,给定的方法将不是可调用的,而是类的属性。换句话说,你不能像self.get_absolute_url() 那样称呼它。

    你可能会问,那么真正的区别是什么?没有参数,就没有真正的区别。但是使用装饰器,您可以保证它是一个属性,以便您可以为装饰器提供额外的参数,以指示该属性的 setter/getter 方法。像这样:@property(fget=foo,fset=goo)

    【讨论】:

      猜你喜欢
      • 2011-06-16
      • 2011-02-20
      • 1970-01-01
      • 1970-01-01
      • 2010-12-21
      • 2019-12-26
      • 2011-09-03
      • 2019-10-28
      • 2014-05-19
      相关资源
      最近更新 更多