'How to get only related objects in django serializer with manyToMany?

class BookingSerializer(serializers.ModelSerializer):

    class Meta:
        model = Booking
        fields = "__all__"


class EmployeeSerializer(serializers.ModelSerializer):
    bookings_st = BookingSerializer(many=True, read_only=True)

    class Meta:
        model = Employee
        fields = "__all__"


class ProjectSerializer(serializers.ModelSerializer):
    employees = EmployeeSerializer(read_only=True, many=True)

    class Meta:
        model = Project
        fields = "__all__"
class Employee(models.Model):
    name = models.CharField(max_length=127)
    lastname = models.CharField(max_length=127)


class Project(models.Model):
    title = models.CharField(max_length=127)
    employees = models.ManyToManyField(Employee,
                                       related_name='employees')

class Booking(models.Model):
    start = models.DateField()
    end = models.DateField()
    employee = models.ForeignKey(Employee,
                                 on_delete=models.CASCADE,
                                 related_name='bookings_st')
    project = models.ForeignKey(Project,
                                on_delete=models.CASCADE,
                                related_name='bookings_st')

I get nested object, but how to get in Emploee only related to both (project and employee) bookings? Now I just get all bookings that this employee has. I mean that structure: project_1: emploee_1: [bookings_that_belong_to_THIS_PROJECT]



Solution 1:[1]

A possibility here is to leverage a SerializerMethodField together with the serializer's context object:

class BookingSerializer(serializers.ModelSerializer):
    class Meta:
        model = Booking
        fields = "__all__"


class EmployeeSerializer(serializers.ModelSerializer):
    bookings_st = serializers.SerializerMethodField()

    def get_bookings_st(self, employee):
        project = self.context.get("project")
        return BookingSerializer(
            employee.bookings_st.filter(project=project), 
            many=True,
        ).data

    class Meta:
        model = Employee
        fields = "__all__"


class ProjectSerializer(serializers.ModelSerializer):
    employees = serializers.SerializerMethodField()

    def get_employees(self, project):
        return EmployeeSerializer(
            project.employees.all(),
            many=True,
            context={**self.context, "project": project}
        ).data

    class Meta:
        model = Project
        fields = "__all__"

This wouldn't be super performant if you're using that when listing projects or when retrieving a specific project with many employees. Depending on your use case - if you're only using it to retrieve a specific project, for example, you could leverage prefetch_related and the Prefetch class to prefetch custom employees + bookings querysets by filtering out the specific project at hand (and you could then use the regular serializers).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 henriquesalvaro