Save a many-to-many model in Django/REST?

django, django-rest-framework, many-to-many, python, rest

Solution

DRF doesn't works create models which are nested serializers objects or Many to Many fields. So is necessary to override Serializer create method and create/get M2M models before create ProjectNode. Try to override `create(self, validated_data)` in your serializer and work with your data inside this method..

Example:

My model Project has M2M relation with ProjectImages. In ProjectSerializer I override create method like this.

 def create(self, validated_data):
        try:
            # Remove nested and M2m relationships from validated_data
            images = validated_data.pop('projectimage_set') if 'projectimage_set' in validated_data else []

            # Create project model
            instance = Project(**validated_data)
            if status:
                instance.set_status(status)

            project = instance.save()

            # Create relations
            for image in images:
                ProjectImage.objects.create(project=project, **image)

        except exceptions.ValidationError as e:
            errors_messages = e.error_dict if hasattr(e, 'error_dict') else e.error_list
            raise serializers.ValidationError(errors_messages)

        return project

Hope this help!

Problem

I'm writing a REST API for my Django app, and can't get POST requests to work on one model. Here's the model in question: ``` class ProjectNode(models.Model): name = models.CharField(max_length=60) place = models.CharField(max_length=150) time_spent = models.BigIntegerField() parent_project = models.ForeignKey(Project, related_name='tasks') workers = models.ManyToManyField(User, related_name='tasks_can_do') def __str__(self): return self.name ``` The `User` model just holds a `name` field at the moment. Here's my serializer for `ProjectNode`: ``` class ProjectNodeSerializer(serializers.ModelSerializer): class Meta: model = ProjectNode fields = ('id', 'name', 'place', 'time_spent', 'workers',) ``` And here's the API view (from `views.py`): ``` class WebProjectNodeListView(generics.ListCreateAPIView): queryset = ProjectNode.objects.all() serializer_class = ProjectNodeSerializer def pre_save(self, obj): obj.parent_project = Project.objects.get(pk=self.request.DATA['parent_project']) for worker_pk in self.request.DATA['workers']: obj.workers.add(User.objects.get(pk=worker_pk)) obj.final_worker = User.objects.get(pk=self.request.DATA['final_workers']) ``` I tried a simpler version yesterday at first, which only had the `Project` ForeignKey relationship, and it seemed to work, so I thought that using `add` would work too, but I get an error when testing out the API with `httpie` (I already added some users and projects, and am sure I get their id's correctly). Here's the request: ``` http POST :8000/api/tasks/ name="newtask" place="home" time_spent:=50 parent_project:=1 workers:=[1] ``` And I get this error: ``` "<ProjectNode: newtask>" needs to have a value for field "projectnode" before this many-to-many relationship can be used. ``` And the traceback also points to this line of code: ``` obj.workers.add(User.objects.get(id=worker_pk)) ``` Now, I get the feeling that this is because I'm trying to update the relationship on the `User` object before a `ProjectNode` object is created in the database, but I'm not sure how to resolve this?

Original source

Related problems