0

Example Json

  {
    "name": "asdfg",
    "amount": {
      "amount": 5000,
      "forexAmount": 10,
      "rateOfExchange": 500,
      "currency": "$",
      "isDebit": false
    }
  }

Want to create a custom field which accepts amount. and perform calculations like ModelName.objects.filter(amount.isDebit=True).aggregate(Sum('amount.amount'))

I am using following code. Issue with following field is its creating multiple fields amount_amount

Django Model

from django.db import models
class Ledger(models.Model):
    name   = models.CharField(max_length=100)
    amount = AmountField()

Custom Django Model Field

from typing import Any, Type
from django.db import models
from django.db.models import Model
from django.db.models.query_utils import DeferredAttribute
from django.db.models.utils import AltersData
from django.utils.translation import gettext_lazy as _
class Amount():
    amount:float
    forexAmount:float|None
    rateOfExchange:float|None
    currency:str|None
    isDebit:bool

    def __init__(self,amount,isDebit,currency=None,forexAmount=None,rateOfExchange=None) -> None:
        self.amount = amount
        self.forexAmount = forexAmount
        self.rateOfExchange = rateOfExchange
        self.isDebit = isDebit
        self.currency = currency

class FieldAmount(Amount,AltersData):
    def __init__(self, instance, field, name):
        super().__init__(None, name)
        self.instance = instance
        self.field = field
        self.storage = field.storage
        self._committed = True


class AmountDescriptor(DeferredAttribute):
    def __get__(self,instance,cls=None):
        if instance is None:
            return self
        data = instance.__dict__
        amount = super().__get__(instance, cls)
        # if(isinstance(amount,Amount)) or amount is None:
        #     attr = self.field.attr_class(instance, self.field, amount)
        #     data[self.field.attname] = attr
        #     pass
        # else :
        #     val = Amount(5,False)
        #     data[self.field.attname] = val
        
        return data[self.field.attname]
    
    def __set__(self, instance, value):
        if(isinstance(value,Amount)):
            data = instance.__dict__
            data[self.field.attname] = value
            data[self.field.attname+"_amount"] = value.amount
            data[self.field.attname+"_forexAmount"] = value.forexAmount


class AmountField(models.Field):

    attr_class = FieldAmount
    descriptor_class = AmountDescriptor


    description = _("Tally Amount")


    def __init__(self, *args: Any, **kwargs: Any) -> None:
        super().__init__(*args, **kwargs)

    def deconstruct(self) -> Any:
        return super().deconstruct()
    
    def from_db_value(self,value):
        if value is None:
            return value
        return value
    

    
    def to_python(self, value: Any) -> Any:
        return super().to_python(value)
    
    def contribute_to_class(self, cls: type[Model], name: str, private_only: bool = ...) -> None:
       
        if not hasattr(self, "_amount_field"):
            amount_field = models.DecimalField(decimal_places=5,max_digits=15)
            amount_field.contribute_to_class(cls,"amount_amount")
            self._amount_field = amount_field
        super().contribute_to_class(cls, name)

        setattr(cls, name, self.descriptor_class(self))

Error: django.db.utils.OperationalError: duplicate column name: amount_amount

References :

sai vineeth
  • 891
  • 2
  • 5
  • 11

0 Answers0