Search code examples
pythondjangodjango-rest-frameworkmany-to-many

Django DRF nested relationships - how to add objects in a ManyToMany field


I am building an API with DRF. I have two models, Folder and User, connected through a ManyToMany field.

models.py

class Folder(models.Model):
    title = models.CharField(max_length=20)
    description = models.CharField(max_length=250)
    organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
    users = models.ManyToManyField(User, related_name='folders')

    def __str__(self):
        return self.title
class User(AbstractBaseUser, PermissionsMixin):
    username = None
    email = models.EmailField(_('email address'), unique=True)
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)
    organization = models.ForeignKey(
        Organization, on_delete=models.CASCADE, null=True, blank=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = UserManager()

    def __str__(self):
        return self.email

serializers.py

class FolderSerializer(serializers.ModelSerializer):

    class Meta:
        model = Folder
        fields = ("id", "title", "description", "users", "organization")

    def create(self, validated_data):
        users = validated_data.pop('users') if 'users' in validated_data else []
        folder = Folder.objects.create(**validated_data)
        for user in users:
            if user in User.objects.all():
                User.objects.filter... **not sure**
            else  
                User.objects.create(folder=folder, **user)
        return folder

The part I am stuck on is the custom create method: basically, users do not get created when the folder is created, they just get added to the newly created folder, so I think that in the for loop for user in users I should check if user exists within the instances of model User and if it does, I should update its property folder. I have no idea how to do so though.

Also, I am not sure if this is the right approach to achieve what I need: a list of users that can be added to folders. Each folder can have many users and each user can be in many folders.

By the way, I also did customize the POST request in the view but it does not work. I'll add it here just to give a complete overview of the current code.

views.py

class FolderViewSet(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated, ]
    serializer_class = FolderSerializer

    def get_queryset(self):
        a = Folder.objects.filter(
            organization=self.request.user.organization)
        b = a.filter(users__id=self.request.user.id)
        return b.order_by('title')

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        folder = serializer.save(users=[].append(self.request.user), organization=self.request.user.organization)
        return Response(FolderSerializer(folder, context=self.get_serializer_context()).data)

Thanks a lot in advance for helping out, cheers.


Solution

  • You're almost there! For setting the users to the folder, you can use m2m set to add all those users to the folder like this:

        def create(self, validated_data):
            users = validated_data.pop('users') if 'users' in validated_data else []
            folder = Folder.objects.create(**validated_data)
            folder.users.set(users)
            return folder
    

    I believe users here are already instances of User so this should work.