Home > OS >  How to get only related objects in django serializer with manyToMany?
How to get only related objects in django serializer with manyToMany?

Time:04-05

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]

CodePudding user response:

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).

  • Related