在Django模型中拥有自定义实例属性的正确方法是什么?

Rég*_* B. 8 python django django-models

我想为Django模型的实例添加自定义属性.这些属性不应存储在数据库中.在任何其他类中,属性将仅由__init__方法初始化.

我已经可以看到三种不同的方法,而且没有一种方法是完全令人满意的.我想知道是否有更好/更多的pythonic/djangoist方法呢?

  1. 覆盖__init__方法:语法是有点令人费解,但它的作品.

    from django.db.models import Model
    
    class Foo(Model):
      def __init__(self, *args, **kwargs):
         super(Model, self).__init__(*args, **kwargs)
         self.bar = 1
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用Django post_init信号:这需要类定义之外的类代码,这是不可读的.

    from django.dispatch import receiver
    from django.db.models.signals import post_init
    @receiver(post_init, sender=Foo)
        def user_init(sender, instance, *args, **kwargs):
          instance.bar = 1
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用实例方法而不是属性:引发一般异常,因为默认行为有点令人不安.

    class Foo(Model):
      def bar(self):
        try:
          return self.bar
        except:
          self.bar = 1
        return self.bar
    
    Run Code Online (Sandbox Code Playgroud)

在这三个选择中,第一个看起来对我来说是最差的.你怎么看?还有其他选择

Bry*_*yan 7

我会使用python中提供的属性装饰器

class Foo(Model):
    @property
    def bar(self):
        if not hasattr(self, '_bar'):
            self._bar = 1

        return self._bar
Run Code Online (Sandbox Code Playgroud)

然后您可以像属性一样访问它而不是使用()调用函数

通过内置后备而不是存储,您甚至可以更直接地使用它

class Foo(Model):
    @property
    def bar(self):
        return getattr(self, '_bar', 1)
Run Code Online (Sandbox Code Playgroud)

  • 回到我这个问题的时候,我带了两年多的Python(2013年!那时我还年轻又天真……)。我想今天我会同意你的回答。@property方法是非常Python的。另一方面,django模型的构造函数很少被覆盖。 (2认同)

Paw*_*iak 4

覆盖__init__才是正确的做法。