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

I am writing a REST API for my Django application and cannot receive POST requests to work on one model. Here is 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 simply holds the name field at the moment. Here is my serializer for ProjectNode :

 class ProjectNodeSerializer(serializers.ModelSerializer): class Meta: model = ProjectNode fields = ('id', 'name', 'place', 'time_spent', 'workers',) 

And here is the kind of API (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']) 

At first I tried a simpler version that only had Project ForeignKey relationships, and it seemed to work, so I thought using add would work too, but I get an error when testing the API with httpie (I already added some users and projects, and I’m sure that I returned them 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 trace also points to this line of code:

 obj.workers.add(User.objects.get(id=worker_pk)) 

Now I get the feeling that this is due to the fact that I'm trying to update the relationship in the User object before creating the ProjectNode object in the database, but I'm not sure how to solve this?

+6
source share
1 answer

DRF does not work by creating models that are nested serializers or Many to Many fields. Therefore, you must override the Serializer creation method and create / get M2M models before creating the ProjectNode. Try to override create(self, validated_data) in your serializer and work with your data inside this method.

Example:

My project model has M2M relevance for ProjectImages. In ProjectSerializer, I override a 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!

+1
source

Source: https://habr.com/ru/post/971834/


All Articles