属性是否适用于django模型字段?

Jia*_*aro 37 python django model properties

我认为问这个问题的最好方法是使用一些代码......我可以这样做吗?(编辑:答案:不)

class MyModel(models.Model):    
    foo = models.CharField(max_length = 20)    
    bar = models.CharField(max_length = 20)  

    def get_foo(self):  
        if self.bar:  
            return self.bar  
        else:  
            return self.foo  

    def set_foo(self, input):  
        self.foo = input  

    foo = property(get_foo, set_foo)  
Run Code Online (Sandbox Code Playgroud)

或者我必须这样做:

是的,你必须这样做:

class MyModel(models.Model):
    _foo = models.CharField(max_length = 20, db_column='foo')
    bar = models.CharField(max_length = 20)

    def get_foo(self):
        if self.bar:
            return self.bar
        else:
            return self._foo

    def set_foo(self, input):
        self._foo = input

    foo = property(get_foo, set_foo)
Run Code Online (Sandbox Code Playgroud)

注意:通过将db_column传递给模型字段,可以将列名保留为数据库中的'foo'.当您处理现有系统并且不希望无缘无故地进行数据库迁移时,这非常有用

And*_*ler 20

模型字段已经是属性,所以我想你必须以第二种方式来避免名称冲突.

当您定义foo = property(..)时,它实际上会覆盖foo = models ..行,因此该字段将不再可访问.

您需要为属性和字段使用不同的名称.实际上,如果你按照示例#1中的方式执行它,当你尝试访问属性时,你会得到一个无限循环,因为它现在试图返回它自己.

编辑:也许您还应该考虑不使用_foo作为字段名称,而是使用foo,然后为您的属性定义另一个名称,因为属性不能在QuerySet中使用,因此当您执行某个操作时,您需要使用实际的字段名称过滤器例如.

  • 关于编辑,这是一个很好的建议 - 我维护一个现有系统,因为必须更改(或属性)字段的名称,我们放弃了这种方法.这项技术可能会在将来变得有用:) (2认同)
  • 我在下面提供了“__foo”的案例。使用 foo 作为 Field 并使用 another_foo 作为包装属性将公开 foo 以便直接操作。尽管 Python 和 X 语言的开发人员应该知道他在做什么 - 隐藏变量被接受为该语言的一部分是有原因的。 (2认同)

Yau*_*ich 17

如上所述,实现自己的django.db.models.Field类的正确替代方法,应该使用 - db_column参数和自定义(或隐藏)类属性.我只是在@Jiaaro的编辑中重写代码,遵循python中更严格的OOP约定(例如,如果_foo实际上应该被隐藏):

class MyModel(models.Model):
    __foo = models.CharField(max_length = 20, db_column='foo')
    bar = models.CharField(max_length = 20)

    @property
    def foo(self):
        if self.bar:
            return self.bar
        else:
            return self.__foo

    @foo.setter
    def foo(self, value):
        self.__foo = value
Run Code Online (Sandbox Code Playgroud)

__foo将被解析为_MyModel__foo(由dir(..)看到)因此隐藏(私有).请注意,此表单还允许使用@property装饰器,这最终是编写可读代码的更好方法.

同样,django将创建带有两个字段foobar的*_MyModel表.

  • 只是注意: - > Django 2.0给出错误:fields.E002)字段名称不能包含"__"' (2认同)

Jus*_*der 5

之前的解决方案受到影响,因为@property导致admin和.filter(_foo)出现问题.

更好的解决方案是覆盖setattr,但这会导致从DB初始化ORM对象时出现问题.然而,有一个解决这个问题的技巧,它是普遍的.

class MyModel(models.Model):
    foo = models.CharField(max_length = 20)
    bar = models.CharField(max_length = 20)

    def __setattr__(self, attrname, val):
        setter_func = 'setter_' + attrname
        if attrname in self.__dict__ and callable(getattr(self, setter_func, None)):
            super(MyModel, self).__setattr__(attrname, getattr(self, setter_func)(val))
        else:
            super(MyModel, self).__setattr__(attrname, val)

    def setter_foo(self, val):
        return val.upper()
Run Code Online (Sandbox Code Playgroud)

秘密是' 自我中的名字.__ dict__ '.当模型从__dict__初始化为new或hydrated时!