I have this model called Menu which has a many-to-many relationship with another model called category. Both this models have a field called is_active which indicates that menu or category is available or not. Alright, then I have an api called RestaurantMenus, which returns all active menus for a restaurant with their categories extended, the response is something like this:
Menu 1
Category 1
Category 2
Menu 2
Category 3
Menu 3
Category 4
Category 5
Category 6
Now what I try to achieve is to only seriliaze those menus and categories which are active (is_active = True). To filter active menus is simple but to filter its children is what I'm struggling with.
My Models:
class Category(models.Model):
menu = models.ForeignKey(Menu, related_name='categories', on_delete=models.CASCADE)
name = models.CharField(max_length=200)
class Menu(models.Model):
name = models.CharField(max_length=200)
My Serializers:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = "__all__"
class MenuSerializer(serializers.ModelSerializer):
categories = CategorySerializer(many=True, read_only=True)
class Meta:
model = Menu
fields = "__all__"
P.S. Category model itself has a many-to-many relationship with another model Called Item, which has an is_active field too. I want the same effect for those too but I cut it from the question cause I think the process should be the same. So actually the api response is something like this:
Menu 1
Category 1
Item 1
Item 2
Item 3
Category 2
Item 4
Here you can use Django Prefetch
objects. This lets you define queryset to choose the set objects from.
So, you would write your Menu
retrieval query something like this:
from django.db.models import Prefetch
menus = Menu.objects.filter(is_active=True).prefetch_related(Prefetch('categories', queryset=Category.objects.filter(is_active=True)))
To add category items as well to the result set, use the following query:
menus = Menu.objects.filter(is_active=True).prefetch_related(Prefetch('categories', queryset=Category.objects.filter(is_active=True)), Prefetch('categories__items', queryset=Item.objects.filter(is_active=True))))
This should solve your problem.
Note: I have not tested the code so you might need to make some modifications.