10

I'm using Django 2.x

I have a model like

class MyModel(models.Model):
    name = models.CharField()
    balance = models.IntegerField()

I want to change the value of balance on the GET request without changing the value in the database.

Like if it could be @Property field, the model will look like

class MyModel(models.Model):
    name = models.CharField()
    balance = models.IntegerField()

    @property
    def balance(self):
        if balance:
           return balance
        return 0.15 * 50

But redeclaration is not allowed. How can I solve this issue?

Note: Field should be compatible with ModelAdmin and DRF Serializer

rahul.m
  • 5,572
  • 3
  • 23
  • 50
Anuj TBE
  • 9,198
  • 27
  • 136
  • 285

2 Answers2

20

There are two ways. Either by using a getter/setter and hide the actual table field. That would allow you to use myobject.balance like any regular field in the model, assigning to it with myobject.balance = 123 and reading from it print(myobject.balance) etc.

class MyModel(models.Model):
    name = models.CharField()
    _balance = models.IntegerField()

    @property
    def balance(self):
        if self._balance:
           return self._balance
        return 0.15 * 50

    @balance.setter
    def balance(self, value):
        self._balance = value

Using a leading _ is the Python convention for "hidden" (private) fields.

A second and simpler way would be to simply use a get_balance() function, and not use a property.

    def get_balance(self):
        if self.balance:
           return self.balance
        return 0.15 * 50
C14L
  • 12,153
  • 4
  • 39
  • 52
  • imagine I already had the field, can I add getter/setter and change the field name without causing migrations? something like `_balance = models(db_field_name='balance')` – EralpB Aug 05 '20 at 17:18
  • 3
    Disclaimer: cannot use the first method to make database entries using balance using a serializer in DRF – Nikhil Pareek Aug 18 '20 at 19:58
0

To extend C14L's answer, the getter/setter can be used in a DRF serializer but you have to declare it explicitly since the ModelSerializer introspection only look to fields (and not properties and methods) as it's explained by Michael Rigoni in his answer to Problems to serialize property (getter and setter) from a model using Django Rest Framework.

class MyModelSerializer(serializers.ModelSerializer):
    balance = serializers.IntegerField()

    class Meta:
        model = MyModel
        fields = ("name", "balance")
double-beep
  • 5,031
  • 17
  • 33
  • 41
BiBzz
  • 5
  • 1
  • 4