• (项目)生鲜超市(七)


    八、商品详情页功能

    1、viewsets实现商品详情页接口

      商品的轮播图是一个外键,序列化的时候需要用嵌套的方式来实现:

     1 class GoodsImageSerializer(serializers.ModelSerializer):
     2     """商品轮播图"""
     3 
     4     class Meta:
     5         model = GoodsImage
     6         fields = ('image',)
     7 
     8 
     9 class GoodsSerializer(serializers.ModelSerializer):
    10     # 覆盖外键字段
    11     category = CategorySerializer()
    12 
    13     # images是设置的related_name="images",把轮播图嵌套进来
    14     images = GoodsImageSerializer(many=True)
    15 
    16     class Meta:
    17         model = Goods
    18         fields = '__all__'

      商品详情页面只需要在商品列表页的接口中继承mixins.RetrieveModelMixin就可以了:

     1 class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
     2     """商品列表页面"""
     3 
     4     pagination_class = GoodsPagination
     5     queryset = Goods.objects.all().order_by('id')  # 必须定义一个默认的排序,否则会报错
     6     serializer_class = GoodsSerializer
     7     filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
     8 
     9     # 自定义过滤类
    10     filter_class = GoodsFilter
    11 
    12     # 搜索,=name表示精确搜索,也可以使用正则
    13     search_fields = ('name', 'goods_brief', 'goods_desc')
    14 
    15     # 排序
    16     ordering_fields = ('sold_num', 'shop_price')

      现在就可以获取到某一个商品的详细数据了:

    2、热卖商品接口实现

      只需要在goods/filter.py中加上is_hot的过滤条件即可:

     1 class GoodsFilter(django_filters.rest_framework.FilterSet):
     2     """商品过滤"""
     3 
     4     # name是要过滤的字段,lookup是执行的行为
     5     pricemin = django_filters.NumberFilter(field_name="shop_price", lookup_expr='gte')
     6     pricemax = django_filters.NumberFilter(field_name="shop_price", lookup_expr='lte')
     7     top_category = django_filters.NumberFilter(field_name="category", method='top_category_filter')
     8 
     9     def top_category_filter(self, queryset, name, value):
    10         # 不管当前点击的是一级分类二级分类还是三级分类,都能找到
    11         return queryset.filter(Q(category_id=value) | Q(category__parent_category_id=value) | Q(
    12             category__parent_category__parent_category_id=value))
    13 
    14     class Meta:
    15         model = Goods
    16         fields = ['pricemin', 'pricemax', 'is_hot']

      然后在后台中将商品的是否热销选为True,现在点开商品详情,最下面有热卖商品就会显示出来:

    3、用户收藏接口

      在user_operation下新建serializers.py文件,序列化用户收藏model的字段:

     1 from rest_framework import serializers
     2 from rest_framework.validators import UniqueTogetherValidator
     3 
     4 from .models import UserFav
     5 
     6 
     7 class UserFavSerializer(serializers.ModelSerializer):
     8     # 获取当前登录的用户
     9     user = serializers.HiddenField(default=serializers.CurrentUserDefault())
    10 
    11     class Meta:
    12         # validate实现唯一联合,一个商品只能收藏一次
    13         validators = [
    14             UniqueTogetherValidator(
    15                 queryset=UserFav.objects.all(),
    16                 fields=('user', 'goods'),
    17                 # message的信息可以自定义
    18                 message="已收藏"
    19             )
    20         ]
    21         model = UserFav
    22         # 收藏的时候需要返回商品的id,因为取消收藏的时候必须知道商品的id是多少
    23         fields = ('user', 'goods', 'id')

      然后在views.py中编写用户收藏的接口,收藏需要继承CreateModelMixin(添加收藏),DestroyModelMixin(删除收藏),ListModelMixin(获取已收藏的商品列表),RetrieveModelMixin(用于查询该商品是否被收藏):

     1 from rest_framework import mixins, viewsets
     2 
     3 from .serializers import UserFavSerializer
     4 from .models import UserFav
     5 
     6 class UserFavViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin,
     7                      mixins.RetrieveModelMixin, viewsets.GenericViewSet):
     8     """用户收藏"""
     9 
    10     queryset = UserFav.objects.all()
    11     serializer_class = UserFavSerializer

      注册url:

    1 router.register(r'userfavs', UserFavViewSet, base_name='userfavs')  # 用户收藏

      然后测试该接口,收藏三个商品,查看已收藏列表:

      重复收藏商品会提示已收藏:

    4、drf的权限验证

      在utils下新建permissions.py,这个官网有实例,直接复制过来即可,把其中的owner改为user即可:

     1 from rest_framework import permissions
     2 
     3 
     4 class IsOwnerOrReadOnly(permissions.BasePermission):
     5     """
     6     Object-level permission to only allow owners of an object to edit it.
     7     Assumes the model instance has an `owner` attribute.
     8     """
     9 
    10     def has_object_permission(self, request, view, obj):
    11         # Read permissions are allowed to any request,
    12         # so we'll always allow GET, HEAD or OPTIONS requests.
    13         if request.method in permissions.SAFE_METHODS:
    14             return True
    15 
    16         # Instance must have an attribute named `owner`.
    17         # obj相当于数据库中的model,这里要把owner改为我们数据库中的user
    18         return obj.user == request.user

      在用户收藏接口中完善权限,收藏只有登录用户才能收藏且必须是当前登录用户,用户只能获取到自己收藏的列表,不能获取全部:

     1 class UserFavViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin,
     2                      mixins.RetrieveModelMixin, viewsets.GenericViewSet):
     3     """用户收藏"""
     4 
     5     serializer_class = UserFavSerializer
     6 
     7     # permission是权限验证 IsAuthenticated必须登录用户 IsOwnerOrReadOnly必须是当前登录的用户
     8     permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
     9 
    10     # authentication是用户认证
    11     authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    12 
    13     # 搜索的字段
    14     lookup_field = 'goods_id'
    15 
    16     # 只能查看当前登录用户的收藏,不会获取所有用户的收藏
    17     def get_queryset(self):
    18         return UserFav.objects.filter(user=self.request.user)
    • JSONWebTokenAuthentication认证不应该全局配置,因为用户获取商品信息或者其它页面的时候并不需要此认证,所以这个认证只要局部中添加就可以
    • 删除settings中的rest_framework_jwt.authentication.JSONWebTokenAuthentication

    5、Vue和用户收藏接口联调

      修改Vue前端代码中的host:

     1 //收藏
     2 export const addFav = params => { return axios.post(`${host}/userfavs/`, params) }
     3 
     4 //取消收藏
     5 export const delFav = goodsId => { return axios.delete(`${host}/userfavs/`+goodsId+'/') }
     6 
     7 export const getAllFavs = () => { return axios.get(`${host}/userfavs/`) }
     8 
     9 //判断是否收藏
    10 export const getFav = goodsId => { return axios.get(`${host}/userfavs/`+goodsId+'/') }

  • 相关阅读:
    c#异步执行方法
    sql 增加、修改、删除触发器小例子
    c#解决高并发加锁(Lock)
    sql中写事物和c#中执行事物
    socket 服务器浏览器与服务器客户端实例
    c# 写txt
    vs2003 序列化json
    一个完整的Windows 服务从创建到安装卸载
    js封装长度验证
    jquery 右下角弹出框
  • 原文地址:https://www.cnblogs.com/Sweltering/p/10024877.html
Copyright © 2020-2023  润新知