1

I am trying to add multiple ManytoMany relationship in a model but when I am trying to add the data it shows OrderedDict() in the validated data in serializer

Models.py

class Client(models.Model):
    
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
    client_name = models.CharField(max_length=500, default=0)
    client_shipping_address = models.CharField(max_length=500, default=0,blank=True, null=True)


class Group(models.Model):

    emp = models.ForeignKey(Employee, on_delete=models.CASCADE)  #try user
    name = models.CharField(max_length=500, default=0)
    groupmodels = models.ManyToManyField(GroupModels)
    sender_clients = models.ManyToManyField(Client)
    receiver_clients = models.ManyToManyField(ReceiverClient)
    warehouses = models.ManyToManyField(Warehouse)

Views.py

class GroupsCreateAPIView(CreateAPIView):
    permission_classes = (permissions.IsAuthenticated,)

    def post(self, request, *args, **kwargs):
        d = request.data.copy()
        print(d)
        serializer = GroupsSerializer(data=d)

        if serializer.is_valid():
            serializer.save()
            print("Serializer data", serializer.data)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            print('error')
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Serilalizer.py

class GroupSenderClientSerializer(serializers.ModelSerializer):

    class Meta:
        model = Client
        fields = "__all__"
        read_only_fields = ('user',)


class GroupsSerializer(serializers.ModelSerializer):

    groupmodels = GroupModelsSerializer(many=True)
    sender_clients = GroupSenderClientSerializer(many=True)
    receiver_clients = ReceiverClientSerializer(many=True)
    warehouses = WarehouseSerializer(many=True)

    class Meta:
        model = Group
        fields = "__all__"


    def create(self, validated_data):
        print("v data", validated_data)
        items_objects = validated_data.pop('groupmodels', None)
        sc_objects = validated_data.pop('sender_clients', None)
        rc_objects = validated_data.pop('receiver_clients', None)
        ware_objects = validated_data.pop('warehouses', None)
        prdcts = []
        sc = []
        rc = []
        ware = []
        for item in items_objects:
            i = GroupModels.objects.create(**item)
            prdcts.append(i)
        instance = Group.objects.create(**validated_data)
        print("sc objects", sc_objects)

        if len(sc_objects)>0:
            for i in sc_objects:
                print("id", i['id'])
                inst = Client.objects.get(pk=i['id'])
                sc.append(inst)

        if len(rc_objects)>0:
            for i in rc_objects:
                inst = ReceiverClient.objects.get(pk=i['id'])
                rc.append(inst)

        if len(ware_objects)>0:
            for i in ware_objects:
                inst = Warehouse.objects.get(pk=i['id'])
                ware.append(inst)

        instance.groupmodels.set(prdcts)
        instance.sender_clients.set(sc)
        instance.receiver_clients.set(rc)
        instance.warehouses.set(ware)
        return instance

The initial data in the serializer is like the following

initial_data = {'name': '546', 'emp': 14, 'sender_clients': [{'id': 3}, {'id': 4}], 'receiver_clients': [], 'warehouses': [], 'groupmodels': []}


validated_data = {'groupmodels': [], 'sender_clients': [OrderedDict(), OrderedDict()], 'receiver_clients': [], 'warehouses': [], 'name': '546', 'emp': <Employee: Employee object (14)>}

Please help me figure out why the sender_clients is converted to blank dicts and how do I change it?

6
  • Can you add your view's code? Serializer's create method is not called. There must be something wrong in your view. I guess serializer.is_valid() and serializer.save() commands are missing. Commented May 25, 2021 at 9:29
  • @ÇağatayBarın I have both of them in the views Commented May 25, 2021 at 10:42
  • Yet you still keep that to yourself only :) Commented May 25, 2021 at 11:25
  • @ÇağatayBarın I have updated the question Commented May 26, 2021 at 5:20
  • Your serializer can't validate your sender_clients data. It has only id but ClientSerializer expects user field. Make the user field on ClientSerializer read only by adding this line below your fields line in ClientSerializer. read_only_fields = ('user', ) Can you do this and try again? Commented May 26, 2021 at 7:34

2 Answers 2

1

when you used ManyToManyField in your Django model I think you don't need to implement any nested serializer class or overwriting action at the create. If you change your serializer to this:

class GroupsSerializer(serializers.ModelSerializer):

    class Meta:
        model = Group
        fields = "__all__"

Django-Rest-Framework add some PrimaryKeyRelatedField fields for each many-many-field in your model to this serializer therefore you repr() object of this serializer at the console probably sew like this:

class GroupsSerializer(serializers.ModelSerializer):

    .....
    groupmodels = PrimaryKeyRelatedField(allow_empty=False, many=True, queryset=GroupModels.objects.all())
    sender_clients = PrimaryKeyRelatedField(allow_empty=False, many=True, queryset=Client.objects.all())
    receiver_clients = PrimaryKeyRelatedField(allow_empty=False, many=True, queryset=ReceiverClient.objects.all())
    warehouses = PrimaryKeyRelatedField(allow_empty=False, many=True, queryset=Warehouse.objects.all())
    .....

therefore you request body for those fields change to this:

{
    .....
    groupmodels: [1,2,3,...],
    sender_clients: [1,2,3,...],
    receiver_clients: [1,2,3,...],
    warehouses: [1,2,3,...],
    .....
}

those ids must be created before, If you want to create at the same time when you was created Group with the duplicated rows at the destination models, should be overwrite with some change in the serializer. But for avoiding to problem and best practice better to implement create action for destination models at the other place like your views or other API for create them. Better to avoiding to implement logic at the serializer. At the future you can control on access on create API for each user role or responsive implementation for each of them.

Sign up to request clarification or add additional context in comments.

Comments

0

Convert the order dict to dict like this:

 data = validated_data.dict()

in your case for list of sc_objects:

objs = [obj.dict() for obj in sc_objects]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.