Как отфильтровать набор запросов на основе поля сериализатора?
Как фильтровать кверисет на основе параметров запроса и динамически вычисляемого поля сериализатора?
Что мне нужно: фильтровать 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
должен быть пропущен.