Django Rest Framework - ListCreateAPIView - Как фильтровать + агрегировать + создавать несколько объектов внутри def perform_create

Любая помощь по этому вопросу будет очень признательна!

В общем, у меня есть модель Transaction, которая связана с моделью User с помощью ForeignKey.

Я хотел бы filter все транзакции, сделанные сегодня, для каждого пользователя, а затем я хочу aggregate их продажи, суммируя транзакции для каждого пользователя, а затем на основе этой суммы я хотел бы рассчитать 10% от нее и create новую транзакцию (в основном сегодняшние заработанные проценты)

Я пытался заставить его работать внутри 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

Который работает! Но он обходит все валидации, когда я делаю:

Transaction.objects.create(owner=user,trans_amt_btc=transaction_amount) 

Проблема в том, что в приведенном выше методе objects.create некоторые поля не упомянуты.

Например, есть поле trans_status, которое находится в модели Transaction (показано ниже), которое имеет null=False и blank=False Но, когда объект создается, он имеет эти поля как null вместо того, чтобы дать мне ошибку

Есть идеи, как я могу реализовать это внутри представления, где я уверен, что проверка может произойти?

Вот поля моей Transaction модели, как они выглядят для справки:

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)

Ниже приведена моя попытка добавить его в view, где, как я надеюсь, я смогу выполнить необходимые проверки , которые не работают :

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

Добавить его в представление - это правильный путь, но я думаю, что вам просто не хватает еще одного сериализатора. Вы должны создать следующий сериализатор, чтобы иметь все необходимые поля:

class TransactionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Transaction
        fields = ['owner', 'trans_amt_btc'] # Add other required fields here

Теперь вам нужно использовать этот сериализатор внутри perform_create следующим образом:

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)
Вернуться на верх