Как отфильтровать набор запросов на основе поля сериализатора?

Как фильтровать кверисет на основе параметров запроса и динамически вычисляемого поля сериализатора?

Что мне нужно: фильтровать GET запрос по параметрам запроса payment_min и payment_max. В простых случаях мы можем выполнить всю фильтрацию через аннотацию, но я не нашел способа запускать пользовательскую функцию на каждом элементе кверисета.

Моя модель

class MortgageOffer(models.Model):
    bank_name = models.CharField(
        'Наименование банка',
        max_length=200,
        unique=True,
    )
    term_min = models.PositiveIntegerField(
        'Срок ипотеки, ОТ',
    )
    term_max = models.PositiveIntegerField(
        'Срок ипотеки, ДО',
    )
    rate_min = models.DecimalField(
        'Ставка, ОТ',
        max_digits=4,
        decimal_places=2,
    )
    rate_max = models.DecimalField(
        'Ставка, ДО',
        max_digits=4,
        decimal_places=2,
    )
    payment_min = models.PositiveIntegerField(
        'Сумма кредита, ОТ',
    )
    payment_max = models.PositiveIntegerField(
        'Сумма кредита, ДО',
    )

    class Meta:
        verbose_name = 'Ипотечное предложение'
        verbose_name_plural = 'Ипотечные предложения'

Мой сериализатор

class MortgageOfferFilteredSerializer(serializers.ModelSerializer):
    payment = serializers.SerializerMethodField()

    class Meta:
        model = MortgageOffer
        fields = '__all__'

    def get_payment(self, obj):
        return calculate_payment(
            int(self.context['request'].query_params['price']),
            int(self.context['request'].query_params['deposit']),
            int(self.context['request'].query_params['term']),
            float(obj.rate_max),
        )

Мой набор представлений

class MortgageOfferViewSet(viewsets.ModelViewSet):
    http_method_names = ['post', 'patch', 'get', 'delete']
    filter_backends = (DjangoFilterBackend,)
    filterset_class = MortgageOfferFilter

    def get_queryset(self):
        return MortgageOffer.objects.all()


    def get_serializer_class(self):
        if self.action in ('create', 'update', 'partial_update'):
            return MortgageOfferWriteSerializer
        elif self.action in ('retrieve', 'list'):
            if self.is_filter_request():
                return MortgageOfferFilteredSerializer
            return MortgageOfferReadSerializer
        return super().get_serializer_class()

    def is_filter_request(self):
        return (self.request.query_params.get('price')
                and self.request.query_params.get('deposit')
                and self.request.query_params.get('term'))

Платеж

def calculate_payment(price, initial_fee, term, yearly_rate):
    """Calculate mortgage monthly payment
    
    A = D * r * (1 + r)^n / ((1 + r)^n - 1), where
    A - monthly payment,
    D - full debt,
    r - monthy rate, 
    n - number of payments.
    D = p * (1 - f), where
    p - mortage subject price,
    f - initial fee in %
    """
    monthly_rate = yearly_rate / 12 / 100
    full_rate = pow(1 + monthly_rate, term * 12) 
    return math.ceil(
        calculate_debt(price, initial_fee) * monthly_rate * full_rate
        / 
        (full_rate - 1)
    )

def calculate_debt(price, initial_fee):
    """Calculate mortgage debt
    
    D = p * (1 - f), where
    p - mortage subject price,
    f - initial fee in %
    """
    return math.ceil(price - price * 0.01 * initial_fee)

Я хочу фильтровать вывод сериализатора MortgageOffer. Любой вывод сериализатора с payment_min > payment, payment > payment_max должен быть пропущен.

Вернуться на верх