user2454305
user2454305

Reputation:

Using properties to modify model field Django

I Have model fields as illustrated below:-

user=models.ForeignKey(CustomUser, null=True)
_corporate = models.CharField(max_length=10, null=True, db_column='corporate')
def set_corporate(self,value):
    if self.user.corporateuser_set.all():
        self._corporate = self.user.corporateuser_set.values_list('company', flat=True)
corporate= property(set_corporate)

Somehow, set_corporate is not being evaluated and therefore _corporate field is not updated.

So what should I do to make it work? what's the best approach here?

I have another model(CorporateUser) with a one to many relationship with User Model, just to clarity of my question.

Upvotes: 2

Views: 3172

Answers (2)

Suor
Suor

Reputation: 3045

Your are doing it wrong in so many ways.

First, properties are used this way in python:

class A:
    @property
    def foo(self):
        return self._foo

    @foo.setter
    def foo(self, value):
        self._foo = value

Or this way:

class A:
    def get_foo(self):
        return self._foo

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

    foo = property(get_foo, set_foo)

Note how value is passed to setter. It should not be computed there as you do. If you need to autoupdate corporate value then you don't need a property, you should overwrite models .save() method or listen to its pre_save signal and update field there.

Second, you should not conditionally set in setter. Setter should always set property to value passed. Like this:

def set_corporate(self, value):
    # If the list is empty then corporate becomes empty
    self._corporate = \
        self.user.corporateuser_set.values_list('company', flat=True)

By violating this rule you will cause grief:

obj.corporate = 'hi'
# obj.corporate is now 'hi'
obj.corporate = ''
# obj.corporate is still 'hi'. WTF?

Third, you should not assign list to CharField. How this supposed to work? It will probably stringify it.

Forth, you are not even assigning a list, you are assigning queryset, which is worse.

Fifth, you are doing essentially same database request twice in a two lines. The efficient way to check if that is empty and then assign is by reusing same queryset:

corporates = self.user.corporateuser_set.values_list('company', flat=True)
if corporates:
    # Stringify it explicitly and our way
    self._corporate = ','.join(corporates)

Upvotes: 2

Daniel Roseman
Daniel Roseman

Reputation: 599470

That's not how you use properties. The first argument to the property function, if you use it like that, is the getter method. You haven't even provided a getter method. You need one which returns the value of self._corporate.

Upvotes: 0

Related Questions