Django模型字段getter/setter

pis*_*hio 21 django django-models

django模型的领域有吸气剂和二传手吗?

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

因为我使用的是python 2.5,所以我不能使用python 2.6 getters/setters.

有帮助吗?

Jos*_*osh 26

您还可以覆盖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)
Run Code Online (Sandbox Code Playgroud)


Dan*_*ead 8

您可以向要保存的模型添加pre_save信号处理程序,在将值保存到数据库之前更新这些值.

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

编辑: 在您的情况下,标准Python属性可能是这样的方式.为Django添加适当的getter/setter支持是一个很长的票,但这不是一个简单的问题需要解决.

您可以使用此博客文章中的技术将属性字段添加到管理员

  • 这可能有用,但吸气剂怎么样? (2认同)

Jus*_*der 5

覆盖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()
Run Code Online (Sandbox Code Playgroud)

秘诀是“ attrname in self .__ dict__ ”。当模型从__dict__的新对象初始化或从__dict__合并时


Pav*_*eev 5

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

例如,如果你有

class MyClass(models.Model):
    my_date = models.DateField()
Run Code Online (Sandbox Code Playgroud)

你可以把它变成

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
Run Code Online (Sandbox Code Playgroud)

并避免任何迁移。

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

  • 注意,您不能将 getter 用作 QuerySet 中的字段,例如“MyClass.objects.filter(my_date=date)”。 (3认同)