开发者

Django model fields getter / setter

开发者 https://www.devze.com 2022-12-31 16:25 出处:网络
is there something like getters an开发者_运维百科d setters for django model\'s fields? For example, I have a text field in which i need to make a string replace before it get saved (in the admin pan

is there something like getters an开发者_运维百科d setters for django model's fields?

For example, I have a text field in which i need to make a string replace before it get saved (in the admin panel, for both insert and update operations) and make another, different replace each time it is read. Those string replace are dynamic and need to be done at the moment of saving and reading.

As I'm using python 2.5, I cannot use python 2.6 getters / setters.

Any help?


You can also override setattr and getattr. For example, say you wanted to mark a field dirty, you might have something like this:

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)


You can add a pre_save signal handler to the Model you want to save which updates the values before they get saved to the database.

It's not quite the same as a setter function since the values will remain in their incorrect format until the value is saved. If that's an acceptable compromise for your situation then signals are the easiest way to achieve this without working around Django's ORM.

Edit: In your situation standard Python properties are probably the way to go with this. There's a long standing ticket to add proper getter/setter support to Django but it's not a simple issue to resolve.

You can add the property fields to the admin using the techniques in this blog post


Overriding setattr is a good solution except that this can cause problems initializing the ORM object from the DB. However, there is a trick to get around this, and it's universal.

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()

The secret is 'attrname in self.__dict__'. When the model initializes either from new or hydrated from the __dict__!


While I was researching the problem, I came across the solution with property decorator.

For example, if you have

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

you can turn it into

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

and avoid any migrations.

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

0

精彩评论

暂无评论...
验证码 换一张
取 消