Eloy Ramirez
Eloy Ramirez

Reputation: 33

django many to many through

I'm trying to implement a coaching system and I'm a little lost about serialization in django.I have a many to many through model to control the appointments and I want to get all data about the coach/coachee involved in the relationship.

class Appointment(models.Model):
    """docstring for Appointment"""
    coach = models.ForeignKey(User, related_name='coaches', on_delete=models.CASCADE)
    coachee = models.ForeignKey(User, related_name='coachees', on_delete=models.CASCADE)
    schedule_date = models.DateField(auto_now=False, auto_now_add=True, blank=True)
    due_date = models.DateField()
    summary = models.TextField(max_length=200)

Using the following serializer I can get the primary keys involved but I'd really like to get the coach and coachee details in one request.

#return appointment data
class AppointmentSerializer(serializers.HyperlinkedModelSerializer):
    """docstring for AppointmentSerializer"""
    class Meta:
        model = Appointment
        fields = ('id', 'schedule_date', 'due_date', 'coach', 'coachee', 'summary', 'condition')

Upvotes: 2

Views: 412

Answers (2)

Ivan Semochkin
Ivan Semochkin

Reputation: 8897

There are several ways to do it. The common one is create serializer for user and use it instead of defaults fields:

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ...

class AppointmentSerializer(serializers.ModelSerializer):
    coach = UserSerializer()
    coachee = UserSerializer()

    class Meta:
        model = Appointment
        fields = ('id', 'schedule_date', 'due_date', 'coach', 'coachee', 'summary', 'condition')

But there will be a problem if you want to use AppointmentSerializer for creating an instance. You will not be able to pass an id's of users to that fields. In that case you could use default fields and override to_representation method.

class AppointmentSerializer(serializers.ModelSerializer):

    class Meta:
        model = Appointment
        fields = ('id', 'schedule_date', 'due_date', 'coach', 'coachee', 'summary', 'condition')

    def to_representation(self, instance):
        representation = super(AppointmentSerializer, self).to_representation(instance)
        representation['coach'] = UserSerializer(instance.coach).data
        representation['coachee'] = UserSerializer(instance.coachee).data
        return representation

Upvotes: 1

Daniel Hepper
Daniel Hepper

Reputation: 29967

Try setting the depth option on the Meta class.

class AppointmentSerializer(serializers.HyperlinkedModelSerializer):
    """docstring for AppointmentSerializer"""
    class Meta:
        model = Appointment
        fields = ('id', 'schedule_date', 'due_date', 'coach', 'coachee', 'summary', 'condition')
        depth = 1

This will generate nested representations.

Alternatively, you can explicitly specify serializers if you need more control.

class AppointmentSerializer(serializers.HyperlinkedModelSerializer):
    coach = CoachSerializer()
    coachee = CoacheeSerializer()

    class Meta:
        model = Appointment
        fields = ('id', 'schedule_date', 'due_date', 'coach', 'coachee', 'summary', 'condition')

You can also add single fields from your related models:

class AppointmentSerializer(serializers.HyperlinkedModelSerializer):
    """docstring for AppointmentSerializer"""
    coach_name = serializers.CharField(source='coach.name')

    class Meta:
        model = Appointment
        fields = ('id', 'schedule_date', 'due_date', 'coach', 'coachee', 'summary', 'condition')

Upvotes: 1

Related Questions