6

I want to set a non-persistent property on a model. I have tried the following:

class class User(models.Model):
    email = models.EmailField(max_length=254, unique=True, db_index=True)

    @property
    def client_id(self):
        return self.client_id

Then:

user = User.objects.create(email='123', client_id=123)
print(user.client_id)

I get the error: can't set attribute. Why?

Prometheus
  • 32,405
  • 54
  • 166
  • 302

1 Answers1

5

You need to define a setter function for your property too, right now, it is read-only (see, e.g., this question).

class class User(models.Model):
    email = models.EmailField(max_length=254, unique=True, db_index=True)

    @property
    def client_id(self):
        return self.internal_client_id

    @client_id.setter
    def client_id(self, value):
        self.internal_client_id = value

Note that I renamed self.client_id to self.internal_client_id, because otherwise, you would be calling the getter and setter functions recursively - the name of the internal variable needs to be different from the property's name.

Of course, if you need to use self.client_id (e.g. because of inheritance), you can also rename the property itself.

Community
  • 1
  • 1
hlt
  • 6,219
  • 3
  • 23
  • 43
  • I did try that but I got ``maximum recursion depth exceeded`` – Prometheus Dec 09 '15 at 13:17
  • That's because your internal variable has the same name as your property, so you'd call the setter recursively. – hlt Dec 09 '15 at 13:18
  • 2
    It should, if `self._client_id` exists (don't forget to update the setter too) – hlt Dec 09 '15 at 13:21
  • If it really looks like this why bothering to write those two property methods at all? Why not simply set and get that attribute. The code has no real effect. – BlackJack Dec 09 '15 at 16:14
  • 1
    @BlackJack In this case, yes. However, properties do have certain advantages over simple attributes (e.g. allowing you to enforce certain constraints on values, etc.) – hlt Dec 09 '15 at 16:22