Any help on this issue would be highly appreciated please!
Basically I have a model called Transaction
and is linked to the User
model using a ForeignKey.
I would like to filter
all transactions made today, per user, and then I want to aggregate
their sales by summing the transactions per user, and then based on this sum, I would want to calculate 10% of it and create
a new transaction (basically today's interest earned)
I have tried to make it work inside inside serializers.py
class UserTransactionFilterSerializer(serializers.Serializer):
username = serializers.CharField(read_only = True)
id = serializers.IntegerField(read_only = True)
agg_amt_btc = serializers.SerializerMethodField(read_only=True)
trans = serializers.SerializerMethodField(read_only = True)
# Gets transaction data using UserTransactionSerializer
def get_trans(self, obj):
user = obj
print(user)
today = timezone.now().date()
my_trans_qs = user.transaction_set.filter(trans_date__date=today)
return TransactionUserInlineSerializer(my_trans_qs, many=True, context = self.context).data
# Aggregates the trans amount (sum and avg)
def get_agg_amt_btc(self, obj):
user = obj
print(user)
today = timezone.now().date()
my_trans_qs = user.transaction_set.filter(trans_date__date=today)
return my_trans_qs.aggregate(sum_btc = Sum('trans_amt_btc'), avg_btc = Avg('trans_amt_btc'))
def create(self,obj):
today = timezone.now().date()
for user in User.objects.filter(transaction__trans_date__date=today).distinct():
total_transactions = user.transaction_set.aggregate(sum_btc = Sum('trans_amt_btc'))['sum_btc']
print(user)
transaction_amount = total_transactions * Decimal('0.1')
print(transaction_amount)
with transaction.atomic():
Transaction.objects.create(owner=user, trans_amt_btc=transaction_amount)
return user
Which works! but it bypasses all validations when I do:
Transaction.objects.create(owner=user,trans_amt_btc=transaction_amount)
The problem is that in the above objects.create
method, some fields are not mentioned.
For example there is a field trans_status
which is found in the Transaction model (shown below) which has null=False
and blank=False
But, when the object gets created, it has these fields as null
instead of giving me an error
Any idea how I can implement this inside a view where I am sure the validation can happen?
Here are the fields of my Transaction
model looks like for your reference:
owner = models.ForeignKey(User, default = 1, null = True, on_delete = models.SET_NULL) #related_name defaults to transaction_set
trans_date = models.DateTimeField(auto_now_add=True, blank=False)
trans_amt_btc = models.DecimalField(decimal_places=12, max_digits=24,blank=False, null=False)
trans_type = models.CharField(choices= TRANSACTION_TYPE_CHOICES, max_length=24, blank=False, null=False)
trans_reason = models.CharField(choices= TRANSACTION_REASON_CHOICES, max_length=24, blank=False, null=False)
trans_mode = models.CharField(choices= TRANSACTION_MODE_CHOICES, max_length=24, blank=False, null=False)
trans_status = models.CharField(choices= TRANSACTION_STATUS_CHOICES, max_length=24, blank=False, default="APPROVED")
note = models.CharField(max_length=120, blank=False, null=False)
Below is my attempt at adding it in the view
, where I hope I can perform the required validations which is not working:
class UserTransactionCommissionView(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserTransactionFilterSerializer
def perform_create(self,serializer):
today = timezone.now().date()
for user in list(User.objects.filter(transaction__trans_date__date=today).distinct()):
total_transactions = user.transaction_set.aggregate(sum_btc = Sum('trans_amt_btc'))['sum_btc']
print(total_transactions)
total_transactions = serializer.validated_data.get('trans_amt_btc')
transaction_amount = total_transactions * Decimal('0.1')
print(transaction_amount)
serializer.save(owner=user)
# with transaction.atomic():
# Transaction.objects.create(owner=user, trans_amt_btc=transaction_amount)
return user
Adding it in the view is the right way to go, but I think you're just missing another serializer. You should create the below serializer in order to have all the needed fields:
class TransactionSerializer(serializers.ModelSerializer):
class Meta:
model = Transaction
fields = ['owner', 'trans_amt_btc'] # Add other required fields here
Now you need to use that serializer inside the perform_create as such:
def perform_create(self, serializer):
today = timezone.now().date()
for user in User.objects.filter(transaction__trans_date__date=today).distinct():
total_transactions = user.transaction_set.filter(trans_date__date=today).aggregate(sum_btc=Sum('trans_amt_btc'))['sum_btc']
if total_transactions:
transaction_amount = total_transactions * Decimal('0.1')
transaction_data = {
'owner': user,
'trans_amt_btc': transaction_amount
# Add other fields here
}
transaction_serializer = TransactionSerializer(data=transaction_data) # <= Call the new serializer
if transaction_serializer.is_valid(): # <= Do the validation
transaction_serializer.save()
else:
raise serializers.ValidationError(transaction_serializer.errors)