R. Wenger
R. Wenger

Reputation: 288

User dependent field as many to many relationship in Django Rest Framework

In my application I have some products, and a logged in user should be able to mark these products as favorites.

I modeled them as a many to many relationship in my models.py, like this:

class Product(models.Model):
    product_name = models.CharField(max_length=200)
    # ...


    def __unicode__(self):
        return self.product_name


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    favorites = models.ManyToManyField(Product)

    @receiver(post_save, sender=User)
    def create_user_profile(sender, instance, created, **kwargs):
        if created:
            Profile.objects.get_or_create(user=instance)

    @receiver(post_save, sender=User)
    def save_user_profile(sender, instance, **kwargs):
        instance.profile.save()

What I'd like to achieve now is that on a product detail view the user can see if the product is already a favorite of his, and should be able to check a box to make it his favorite.

On the model level this is a many to many relationship, but on the view it is more of a boolean relationship (favorite yes/no for current user).

I already managed to have the favorite status displayed in the detail view, with a SerializerMethodField

class ProductSerializer(serializers.ModelSerializer):
    # ...
    favorite = serializers.SerializerMethodField()

    def get_favorite(self, obj):
    try:
        self.context['request'].user.profile.favorites.get(pk=obj.pk)
        return True
    except Product.DoesNotExist:
        return False

What I am struggling with currently is adding a favorite to the current user's list of favorites with this setup, as this SerializerMethodField is read-only and, because of that, doesn't appear in the validated_data in the update() method.

Does anyone have a solution for this or a similar problem?

Upvotes: 2

Views: 935

Answers (1)

Raz
Raz

Reputation: 7923

You can create custom field.

class FavoriteField(serializers.BooleanField):

    def get_attribute(self, instance):
        return self.context['request'].user.profile.favorites.filter(pk=instance.pk).exists()

class ProductSerializer(serializers.ModelSerializer):
    favorite = FavoriteField()

    def update(self, instance, validated_data):
        instance = super().update(instance, validated_data)
        is_favourite = validated_data.get('favorite')  # can be None
        if is_favourite is True:
            self.context['request'].user.profile.favorites.add(instance)
        elif is_favourite is False:
            self.context['request'].user.profile.favorites.remove(instance)
        return instance

Upvotes: 1

Related Questions