Django Фильтрация цикла For Loop с 2 параметрами
Я создал систему уведомлений, которая позволяет пользователю подписаться на пользовательские уведомления (Notification), которые срабатывают на основе выбранного им параметра и порогового значения из другой модели (Report). Моя models.py выглядит следующим образом:
class Report(models.Model):
field1 = models.FloatField()
field2 = models.FloatField()
field3 = models.FloatField()
...
class Notification(models.Model):
threshold_field = models.CharField() # would store field1, field2, field3, etc from Report
threshold_value = models.FloatField() # the value corresponding to threshold_field that would trigger the notification
Я пытаюсь написать запрос к базе данных, который получил бы все Notification, удовлетворяющие критериям для запуска уведомления, заданным набором запросов Report или Report. Однако я не могу понять, как объединить в запросе все возможные threshold_field и threshold_value. Самое уродливое решение, которое могло бы работать, было бы примерно таким:
report = Report.objects.first() # get the report to query
all_fields = Report._meta.get_fields() # all field choices from Report
all_querysets = []
for field in all_fields: # loop through all fields, i.e. field1, field2, field3
qs = Notification.objects.filter(
threshold_field=field,
threshold_value__gte=getattr(report, field) # get the value stored in the field
)
all_querysets.append(qs)
Это некрасиво, но это не ужасное решение, учитывая, что в моем продакшене Report всего ~20 полей. Однако, есть ли лучший способ фильтрации Notification без цикла for? Я знаю, что это было бы возможно, если бы мне нужно было запросить только 1 поле в Notification, но камнем преткновения здесь является то, что и threshold_field, и threshold_value полагаются на цикл.
Я нашел решение, отчасти благодаря этому посту . Вы можете использовать заранее подготовленный запрос Q для применения условного оператора OR к нескольким полям, которые соответствуют двум критериям:
from django.db.models import Q
q_filter = Q(
*[Q(threshold_field=field.name, threshold_value__gte=getattr(Report, field.name)) for field in
Report._meta.get_fields()], _connector=Q.OR
) # complex filter to pair threshold field and threshold
return Notification.objects.filter(q_filter)