I am new to django rest framework, and I am trying to build api for a todo app using which i can add collaborator to a todo my todo model is as follows:
class Todo(models.Model):
creator = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=255)
collaborators = models.ManyToManyField(User,related_name='collaborators')
def __str__(self):
return self.title
Serializer.py
class TodoCreateSerializer(serializers.ModelSerializer):
def save(self, **kwargs):
data = self.validated_data
user = self.context['request'].user
title = data['title']
todo = Todo.objects.create(creator=user, title=title)
return todo
class Meta:
model = Todo
fields = ('id', 'title',)
class UserObjectSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username']
class TodoSerializer(serializers.ModelSerializer):
collaborators = UserObjectSerializer(many=True, required = False)
class Meta:
model = Todo
fields = ['id', 'title', 'collaborators']
class CollaboratorSerializer(serializers.ModelSerializer):
collaborators = UserObjectSerializer(many=True)
class Meta:
model = Todo
fields = ['collaborators']
and when i try to add collaborator object to my collaborator field using the following method in the viewset
class CollaboratorViewSet(viewsets.ModelViewSet):
serializer_class = CollaboratorSerializer
queryset=Todo.objects.all()
@action(methods=['put'], detail=True, permission_classes=[permissions.IsAuthenticated, ], url_path='add-collaborator', url_name='add_collaborator')
def add_collaborator(self, request, pk=None):
try:
todo = Todo.objects.get(pk=pk)
except Exception:
return Response({'Error':'Invalid Id'})
else:
if request.user == todo.creator:
try:
collborators = request.data["collaborators"]
except KeyError:
return Response({'Error':'Collaborator field not specified in request'}, status = status.HTTP_400_BAD_REQUEST)
else:
collab_list = []
for collab in collborators:
try:
collab_name = collab['username']
except KeyError:
return Response({'Error':'No username provided'}, status = status.HTTP_400_BAD_REQUEST)
else:
new_collab = User.objects.filter(username=collab_name)
if new_collab:
collab_list.append(new_collab)
else:
return Response({'detail':'No user with provided username exists'}, status = status.HTTP_400_BAD_REQUEST)
todo.collaborators.add(*collab_list)
return Response({'Success':'Added collaborators successfully'}, status=status.HTTP_200_OK)
else:
raise PermissionDenied("You are not the creator of this Todo.")
@action(methods=['patch'], detail=True, permission_classes=[permissions.IsAuthenticated, ], url_path='delete-collaborator', url_name='delete_collaborator')
I get an error django.db.utils.OperationalError: sub-select returns 11 columns - expected 1 but when i use todo.collaborators.set(collaborator_object) collaborator gets added but this way i am able to add only one collaborator and no effect occurs when i try to add multiple collaborators. I know that we can add multiple object to m2m relation fields using .add() method but that's not working when i try to add even one object, i also went through the documentation for .add() method but could not find any help.
Sorry for such a long question and thanks for helping in advance!
I managed to solve the error, actually I was was trying to access the collaborators as
new_collab = User.objects.filter(username=collab_name)
which will return a queryset even if there is a unique user with given username and then i was trying to add collaborator directly to collaborators field which caused this error as it expected an User instance but I was providing a queryset to avoid that I just replaced the above line as
new_collab = User.objects.get(username=collab_name)
which will return a User object instance if it exists so no error is raised and I am able to add multiple as well as single collaborators.