Django Rest Framework中用户相关字段的多对多关系

时间:2017-02-18 21:43:48

标签: django rest django-rest-framework many-to-many serializer

在我的应用程序中,我有一些产品,登录用户应该能够将这些产品标记为收藏夹。

我在models.py中将它们建模为多对多关系,如下所示:

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()

我现在想要实现的是,在产品详情视图中,用户可以看到该产品是否已经成为他的最爱,并且应该能够选中一个框以使其成为他的最爱。

在模型级别,这是一个多对多关系,但在视图上它更像是一个布尔关系(当前用户最喜欢是/否)。

我已设法在详情视图中显示收藏状态,并显示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

我目前正在努力的是通过此设置为当前用户的收藏列表添加收藏夹,因为此SerializerMethodField是只读的,因此,不会出现在该设置的validated_data中update()方法。

有没有人有解决此问题或类似问题的方法?

1 个答案:

答案 0 :(得分:1)

您可以创建自定义字段。

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