Vaibhav Jain
Vaibhav Jain

Reputation: 5507

DRF Create and Retrieve m2m with through model

I want to save m2m relationship with through model

models.py

from django.db import models

class Student(utils.PersonalDetailsMixin, utils.ContactDetailsMixin, TimeStampedModel):
    guardians = models.ManyToManyField('core.Guardian', through='Relation')

class Relation(models.Model):
    student = models.ForeignKey('core.Student')
    guardian = models.ForeignKey('core.Guardian')
    relation_type = models.CharField(max_length=1, choices=utils.RELATION_CHOICES)
    # Only used when relation_type is Other
    relation_name = models.CharField(max_length=25, null=True, blank=True)

    class Meta:
        unique_together = (
            ('student', 'guardian')
        )

class Guardian(utils.PersonalDetailsMixin, utils.ContactDetailsMixin, TimeStampedModel):
    pass

serializers.py

class StudentSerializer(serializers.ModelSerializer):
    guardians = GuardianSerializer(many=True)

    class Meta:
        model = Student


class GuardianSerializer(serializers.ModelSerializer):
    class Meta:
        model = Guardian

class RelationSerializer(serializers.ModelSerializer):
    class Meta:
        model = Relation

First:

relation_type = serializers.ChoiceField(choices=RELATION_CHOICES)
relation_name = serializers.CharField(max_length=25, required=False, allow_null=True, allow_blank=True)

I tried adding relation_type and relation_name to GuardianSerializer but got this error

Got AttributeError when attempting to get a value for field `relation_type` on serializer `GuardianSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Guardian` instance.
Original exception text was: 'Guardian' object has no attribute 'relation_type'.

Which is fine DRF should give this error.

Second:

class StudentSerializer(serializers.ModelSerializer):
    school = serializers.HiddenField(default='')
    guardians = RelationSerializer(source='relation_set', many=True)

class GuardianSerializer(serializers.ModelSerializer):
    class Meta:
        model = Guardian

class RelationSerializer(serializers.ModelSerializer):
    guardian = GuardianSerializer(many=True)

    class Meta:
        model = Relation

Added RelationSerializer to StudentSerializer and GuardianSerializer to RelationSerializer

Now I am getting 'Guardian' object is not iterable

Traceback:

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  149.                     response = self.process_exception_by_middleware(e, request)

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
  58.         return view_func(*args, **kwargs)

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/rest_framework/viewsets.py" in view
  87.             return self.dispatch(request, *args, **kwargs)

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  466.             response = self.handle_exception(exc)

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  463.             response = handler(request, *args, **kwargs)

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/rest_framework/mixins.py" in list
  48.         return Response(serializer.data)

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/rest_framework/serializers.py" in data
  674.         ret = super(ListSerializer, self).data

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/rest_framework/serializers.py" in data
  239.                 self._data = self.to_representation(self.instance)

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/rest_framework/serializers.py" in to_representation
  614.             self.child.to_representation(item) for item in iterable

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/rest_framework/serializers.py" in to_representation
  472.                 ret[field.field_name] = field.to_representation(attribute)

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/rest_framework/serializers.py" in to_representation
  614.             self.child.to_representation(item) for item in iterable

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/rest_framework/serializers.py" in to_representation
  472.                 ret[field.field_name] = field.to_representation(attribute)

File "/home/prime/.virtualenvs/omapi/local/lib/python2.7/site-packages/rest_framework/serializers.py" in to_representation
  614.             self.child.to_representation(item) for item in iterable

Exception Type: TypeError at /v1/students/
Exception Value: 'Guardian' object is not iterable

How do I save Student instance with Guardian and Relation.How can I achieve this I know a custom create method is required but how do I by pass this error. Or is there any other way to serialize and deserialize this kind of relation.

Upvotes: 0

Views: 1178

Answers (2)

Linovia
Linovia

Reputation: 20986

You'll need to have the MembershipSerializer nested in the GroupSerializer replacing the PersonSerializer and have the MembershipSerializer that has a nested PersonSerializer in order for this to work.

Alternatively, you could replace the PersonSerializer with a regular Serializer and get the dataset explicitly by yourself instead of relying on automated DRF.

Edit following the question edition:

class RelationSerializer(serializers.ModelSerializer):
    guardian = GuardianSerializer(many=True)

Since the relation between Relation and Guardian is a ForeignKey you need to remove the many=True here.

Upvotes: 1

Shubhanshu
Shubhanshu

Reputation: 1015

class MembershipSerializer(serializers.ModelSerializer):
    person = serializers.PrimaryKeyRelatedField(queryset=Person.objects.all())
    group = serializers.PrimaryKeyRelatedField(queryset=Group.objects.all())

    class Meta:
        model = Membership
        fields = ('person', 'group', 'date_joined', 'invite_reason')


class PersonSerializer(serializers.ModelSerializer):

    class Meta:
        fields = ('name')

class GroupSerializer(serializers.ModelSerializer):

    class Meta:
        model = Group
        fields = ('name')

Hope the answer helps :)

Upvotes: 1

Related Questions