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

Я хочу сделать запрос, в котором я могу применять поиск только при выполнении некоторых условий. например

Покупатель может выбрать только ту еду из киоска, за которую он заплатил

class Customer(models.Model):
    food_type = models.CharField()
    fruit_id = models.ForeignKey(Fruit, null=True)
    vegetable_id = models.ForeignKey(Vegetable, null=True)
    is_paid = models.BooleanField()
    
class Food(models.Model):
    fruit_id = models.ForeignKey(Fruit, null=True)
    vegetable_id = models.ForeignKey(Vegetable, null=True)

Итак, мне нужно сделать что-то вроде:

q = Food.objects.all()
if Customer.objects.filter(id=(id of customer), food_type='fruit', is_paid=True).exists():
    q = q.filter(fruit_id__in=Customer.objects.filter(id=(id of customer), food_type='fruit', is_paid=True).values_list('fruit_id', flat=True))

if Customer.objects.filter(id=(id of customer), food_type='vegetable', is_paid=True).exists():
    q = q.filter(vegetable_id__in=Customer.objects.filter(id=(id of customer), food_type='vegetable', is_paid=True).values_list('vegetable_id', flat=True))

Как я могу оптимизировать это, поскольку это небольшой пример, в моем случае есть гораздо больше условий. Я хочу уменьшить количество обращений к базе данных. Также есть ли способ использовать здесь условные выражения? Например, When()

Любая помощь будет оценена по достоинству.

Вы можете использовать Q.

from django.db.models import Q

q = Food.objects.all()
q = q.filter(
    Q(
       vegetable_id__in=Customer.objects.filter(id=(id of customer), food_type='vegetable', is_paid=True).values_list('vegetable_id', flat=True)
    )|Q(
       fruit_id__in=Customer.objects.filter(id=(id of customer), food_type='fruit', is_paid=True).values_list('fruit_id', flat=True)
    )
)

Причина сложности заключается в структуре ваших моделей - у вас клиент связан с фруктами и/или овощами, а продукты питания также связаны с фруктами/овощами, поэтому клиент и продукты питания потенциально связаны только через фрукты/овощи - очень запутанно и долго.

Это также объясняет, почему у вас есть 'food_type' в модели Customer, чтобы попытаться компенсировать это. Я бы предложил гораздо более простую структуру, но с одной дополнительной моделью:

class Customer(models.Model):
    food = models.ManyToManyField(Food, ... # customer can have many Food
    is_paid = models.BooleanField()

# create a new food type model that stores Fruit, Vegetable, etc.
class FoodType(models.Model):
    name = models.CharField(...

class Food(models.Model):
    # food now connects to the food type
    food_type = models.ForeignKey(FoodType, ...

Теперь вы можете делать свои запросы гораздо более краткими:

# get food that the customer has paid for
Food.objects.filter(customer__is_paid=True)

# get fruit that the customer has paid for
Food.objects.filter(customer__is_paid=True, food_type__name="Fruit")
Вернуться на верх