Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django model fields getter / setter

is there something like getters and 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?

like image 843
pistacchio Avatar asked May 24 '10 17:05

pistacchio


3 Answers

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)
like image 181
Josh Avatar answered Nov 08 '22 22:11

Josh


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

like image 41
Dan Head Avatar answered Nov 08 '22 22:11

Dan Head


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__!

like image 6
Justin Alexander Avatar answered Nov 08 '22 22:11

Justin Alexander