美文网首页Django+Vue生鲜电商
【Vue+DRF生鲜电商】18.用户收藏、取消收藏商品接口实现

【Vue+DRF生鲜电商】18.用户收藏、取消收藏商品接口实现

作者: 吾星喵 | 来源:发表于2019-05-30 17:11 被阅读29次

    更多内容请点击 我的博客 查看,欢迎来访。

    用户收藏接口实现

    这个功能属于用户操作的功能,写在 user_operation 应用下

    对于收藏功能,如果点击收藏,相当于是添加一条收藏记录(mixins.CreateModelMixin),如果是取消收藏,则删除收藏记录(mixins.DestroyModelMixin

    用户收藏接口基础

    用户添加收藏序列化

    在 user_operation 应用下创建 serializers.py ,然后创建序列化类UserFavSerializer,用于序列化用户收藏数据

    from rest_framework import serializers
    from .models import UserFav
    
    
    class UserFavSerializer(serializers.ModelSerializer):
        class Meta:
            model = UserFav
            fields = ['user', 'goods']
    

    用户收藏商品ViewSet

    编辑 user_operation 中的 views.py

    # apps/user_operation/views.py
    
    from rest_framework import viewsets, mixins
    from .serializers import UserFavSerializer
    from .models import UserFav
    
    
    class UserFavViewSet(mixins.CreateModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet):
        """
        用户收藏商品
        取消收藏商品
        """
        queryset = UserFav.objects.all()
        serializer_class = UserFavSerializer
    

    用户收藏urls配置

    修改主 urls.py ,添加收藏商品的router

    from user_operation.views import UserFavViewSet
    
    router.register(r'userfavs', UserFavViewSet, base_name='userfavs')  # 用户收藏商品
    

    访问 http://127.0.0.1:8000/userfavs/ 可以看到下面内容

    BLOG_20190530_170240_51

    这里面用户和商品都可以自己选择。但实际上用户是不应该可选的,只需要获取当前登录用户。要收藏商品,只需要传递商品的对象即可。

    所以就需要解决UserFavSerializer中的user如何填充当前用户。

    创建user隐藏字段

    访问 https://www.django-rest-framework.org/api-guide/validators/#advanced-field-defaults 查看具体使用方法

    在序列化器中跨多个字段应用的验证器有时可能需要一个字段输入,这个字段不应该由API客户机提供,但是可以作为验证器的输入。

    可能想要使用两种模式来进行这种验证:

    • 使用HiddenField。该字段将出现在validated_data中,但序列化输出时不会显示出来,可以用于设置当前登录用户
    • 使用带有read_only=True的标准字段,但该字段也包含一个default=…参数。此字段将在序列化器输出表示中使用,但不能由用户直接设置。

    REST框架包含一些缺省值,这些缺省值在此上下文中可能很有用。

    CurrentUserDefault

    可用于表示当前用户的默认类。为了使用它,在实例化序列化器时,request必须作为上下文字典的一部分提供。例如在本项目中

    # apps/user_operation/serializers.py
    
    class UserFavSerializer(serializers.ModelSerializer):
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()  # 表示user为隐藏字段,默认为获取当前登录用户
        )
    
        class Meta:
            model = UserFav
            fields = ['user', 'goods']
    

    此时刷新 http://127.0.0.1:8000/userfavs/ 可以看到user字段已经隐藏了

    BLOG_20190530_170227_67

    如果选中一个商品,点击POST,这时候会向后台提交一个数据,但用户为隐藏提交的

    BLOG_20190530_170221_76

    这时候会返回一个goods.id,现在访问后台查看这条数据,就可以看到

    BLOG_20190530_170213_66

    取消收藏商品(删除数据)

    一般情况在做serializer时,如果有删除操作,就需要将它的id返回回来

    # apps/user_operation/serializers.py
    
    class UserFavSerializer(serializers.ModelSerializer):
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()  # 表示user为隐藏字段,默认为获取当前登录用户
        )
    
        class Meta:
            model = UserFav
            fields = ['user', 'goods', 'id']
    

    再来添加一条数据,就可以得到序列化中的id

    BLOG_20190530_170204_16

    有了这个id,后期做删除功能,也就是取消收藏就简单了。

    列出所有收藏

    在收藏商品ViewSet中,有了添加收藏,删除收藏,也可以有mixins.ListModelMixin显示收藏的功能

    # apps/user_operation/views.py
    
    class UserFavViewSet(mixins.CreateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
        """
        用户收藏商品
        取消收藏商品
        显示收藏商品
        """
        queryset = UserFav.objects.all()
        serializer_class = UserFavSerializer
    

    现在刷新 http://127.0.0.1:8000/userfavs/ ,可以看到所有收藏商品的序列化数据

    BLOG_20190530_170156_44

    现在获取的goods只是id,但有时候也需要商品的其他详情,这个在个人中心,显示商品收藏时完善。

    删除操作url为,DEL /userfavs/id/ ,只需要删除对应收藏的指定id即可

    指定收藏记录的id执行DELETE

    现在来删除id为1的收藏数据,利用工具实现,可以得到下面的204返回值,表明删除成功的。

    BLOG_20190530_170144_36

    刷新 http://127.0.0.1:8000/userfavs/ 可以看到,id为1的数据删除成功了。

    BLOG_20190530_170133_74

    收藏商品数据联合唯一性

    用户反复点击收藏,会多次创建数据,这是不合理的,实际上用户点击收藏会创建一条收藏数据,用户再次点击一次,应该删除该条数据。

    models中配置unique_together保证联合唯一

    设置用户和商品对应联合唯一,当数据已存在时,数据库就会抛出异常

    # apps/user_operation/models.py
    
    class UserFav(models.Model):
        """
        用户收藏
        """
        user = models.ForeignKey(User, verbose_name='用户', help_text='用户', on_delete=models.CASCADE, related_name='favs')
        goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name='商品', help_text='商品', related_name='favs')
        add_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间')
    
        class Meta:
            verbose_name_plural = verbose_name = '用户收藏'
            unique_together = ['user', 'goods']
    
        def __str__(self):
            return "{} 收藏 {}".format(self.user.name if self.user.name else self.user.username, self.goods.name)
    

    设置完成后需要执行makemigrationsmigrate,如果数据库中存在同样的,最后删除再执行

    连续收藏一个商品2次,那么第一个就会抛出异常

    BLOG_20190530_170123_15

    DRF配置UniqueTogetherValidator联合唯一

    也可以自己在serializer中配置,访问 https://www.django-rest-framework.org/api-guide/validators/#uniquetogethervalidator 查看DRF配置。

    在做这个之前,联合唯一也是可以实现的,因为在UserFavSerializer中使用的是ModelSerializer,类似于Django的ModelForm,它需要满足model中配置的条件,因为model中配置了unique_together = ['user', 'goods'],当提交的数据不满足就会抛出上图的异常。

    实际上,DRF也是可以自定义的,UniqueTogetherValidator验证器可用于对模型实例强制unique_together约束。它有两个必需的参数和一个可选的消息参数:

    • queryset: required——这是应该强制惟一性的queryset。
    • fields:required——字段名的列表或元组,应该构成一个惟一的集合。这些字段必须作为字段存在于序列化器类中。
    • message:可选——验证失败时应该使用的错误消息。

    在这个项目中可以如下使用

    # apps/user_operation/serializers.py
    
    from rest_framework import serializers
    from rest_framework.validators import UniqueTogetherValidator
    from .models import UserFav
    
    
    class UserFavSerializer(serializers.ModelSerializer):
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()  # 表示user为隐藏字段,默认为获取当前登录用户
        )
    
        class Meta:
            model = UserFav
            fields = ['user', 'goods', 'id']
            # UserFav项目属于父列表,并且有一个由“position”字段定义的顺序。给定列表中的任何两项不得共享同一位置。
            validators = [
                UniqueTogetherValidator(
                    queryset=UserFav.objects.all(),
                    fields=('user', 'goods'),
                    message='已经收藏'
                )
            ]
    

    注意:UniqueTogetherValidation类总是施加一个隐式的约束,它所应用的所有字段总是按需要处理。具有默认值的字段是一个例外,因为它们总是提供一个值,即使在用户输入中省略了这个值。

    以上validators不是作用域某个字段之上了,需要写在Meta中,因为UniqueTogetherValidator是作用域两个或两个字段以上的,不是针对一个字段,所以需要写在这。

    现在在 http://127.0.0.1:8000/userfavs/ 页面POST相同商品,就会得到如下返回

    BLOG_20190530_170114_89

    non_field_errors表示不能指定某一个字段的错误,而是多个字段造成的错误。可以在前端判断,如果出现non_field_errors字段,则表示整体的错误,不需要写在某个表单下面提示。

    相关文章

      网友评论

        本文标题:【Vue+DRF生鲜电商】18.用户收藏、取消收藏商品接口实现

        本文链接:https://www.haomeiwen.com/subject/yegvtctx.html