Django模型字段getter / setter

时间:2010-05-24 17:02:02

标签: django django-models

django模型的字段有什么类似getter和setter的东西吗?

例如,我有一个文本字段,我需要在它被保存之前进行字符串替换(在管理面板中,对于插入和更新操作),并在每次读取时进行另一个不同的替换。这些字符串替换是动态的,需要在保存和读取时完成。

当我使用python 2.5时,我无法使用python 2.6 getters / setters。

任何帮助?

4 个答案:

答案 0 :(得分:25)

您还可以覆盖setattr和getattr。例如,假设您想要将字段标记为脏,您可能会这样:

class MyModel:
    _name_dirty = False

    name = models.TextField()

    def __setattr__(self, attrname, val):
        super(MyModel, self).__setattr__(attrname, val)

        self._name_dirty = (attrname == 'name')


    def __getattr__(self, attrname):
        if attrname == 'name' and self._name_dirty:
            raise('You should get a clean copy or save this object.')

        return super(MyModel, self).__getattr__(attrname)

答案 1 :(得分:8)

您可以向要保存的模型添加pre_save signal handler,在将值保存到数据库之前更新这些值。

它与setter函数不完全相同,因为在保存值之前,值将保持不正确的格式。如果这对您的情况来说是可接受的折衷方案,那么信号是最简单的方法,无需解决Django的ORM问题。

修改 在您的情况下,标准Python属性可能是这样做的方式。有一个long standing ticket可以为Django添加正确的getter / setter支持,但这不是一个简单的问题需要解决。

您可以使用this blog post

中的技巧将属性字段添加到管理员

答案 2 :(得分:4)

覆盖 setattr 是一个很好的解决方案,除了这会导致从数据库初始化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()

秘密是' attrname in self .__ dict __ '。当模型从 __ dict __ 中的new或hydrated初始化时!

答案 3 :(得分:0)

在研究问题时,我遇到了使用property装饰器的解决方案。

例如,如果您有

class MyClass(models.Model):
    my_date = models.DateField()

您可以将其变成

class MyClass(models.Model):
    _my_date = models.DateField(
        db_column="my_date",  # allows to avoid migrating to a different column
    )

    @property
    def my_date(self):
        return self._my_date

    @my_date.setter
    def my_date(self, value):
        if value > datetime.date.today():
            logger.warning("The date chosen was in the future.")
        self._my_date = value

并避免任何迁移。

来源:https://www.stavros.io/posts/how-replace-django-model-field-property/