zoukankan      html  css  js  c++  java
  • Django REST framework+Vue 打造生鲜电商项目(笔记六)

    (部分代码来自https://www.cnblogs.com/derek1184405959/p/8836205.html)

    九、个人中心功能开发

    1、drf的api文档自动生成

    (1) url

    #drf文档,title自定义
    path('docs',include_docs_urls(title='火影忍者')),

    访问:http://127.0.0.1:8000/docs  就可以自动生成

    (2)drf文档的优点:

    • 自动生成
    • 文档里可以做交互和测试
    • 可以生成js,shell和python代码段

    (3)代码中注释的格式:

    ViewSet的格式,更多请看官方文档

    class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):
        '''
        list:
            商品列表,分页,搜索,过滤,排序
        retrieve:
            获取商品详情
        '''

     (4)Description

    添加字段的描述有三种方式: (help_text等)

    • model的字段中加
    • serializer的字段加
    • filter中也可以加

     2、动态设置serializer和permission获取用户信息

    用户个人信息修改,因为手机号是验证过的,不能随便改

    在会员中心页面,想要获取个人信息,只需在UserViewset中多继承一个类:mixins.RetrieveModelMixin。还要重写get_object(“get_object“是用来控制RetrieveModelMixin),返回登录的用户。这样用户只需在users后面加任意id就行,例users/xxx,都会返回当前用户。

    因为当我们使用RetrieveModelMixin 的时候,会自动帮我们注册个url(前提是我们在url.py里已经用router注册了users),格式是“users/id”。

    另一种方法是可以在re_dict[]里面添加id给返回回去。

    (1)用户详情的序列化

    这里我们要重新写个serializers来显示用户的详细信息

     users/serializers.py

    class UserDetailSerializer(serializers.ModelSerializer):
        """
        用户详情
        """
        class Meta:
            model = User
            fields = ("name", "gender", "birthday", "email","mobile")

    然后在获取用户详情的时候,我们需要用户是登陆状态的,这就要用到"permission_classes = (permissions.IsAuthenticated, )",但是这里有个问题,就是在进入用户详情页需要用户登录,但在用户注册的时候就不需要(“class UserViewset”既有用户注册功能,也有查看详情页等功能),所以就需要有一种动态的方式,在用户注册时不进行身份验证,在进入详情页的时候进行身份验证。

    查看关于permission的源码之后,

    我们就可以把"permission_classes = (permissions.IsAuthenticated, )"改为下面这种

    def get_permissions(self):
            if self.action == "retrieve":
                return [permissions.IsAuthenticated()]
            elif self.action == "create":
                return []
    
            return []

    还有一个,修改完上面的内容后,我们在查看详情页时发现只返回"username"和“mobile”两个字段,这是因为我们设置了“serializer_class = UserRegSerializer“,但这个是我们注册的时候用的,在返回详情页的时候我们希望可以获得更多的数据,就是我们前面“UserDetailSerializer“中的内容,所以,遵循一样的思路。

    在“serializer_class = UserRegSerializer“后面加上这个,

    def get_serializer_class(self):
            if self.action == "retrieve":
                return UserDetailSerializer
            elif self.action == "create":
                return UserRegSerializer
    
            return UserDetailSerializer

     具体过程如下

    (2)users/views.py

    class UserViewset(CreateModelMixin,mixins.RetrieveModelMixin,viewsets.GenericViewSet):
        '''
        用户
        '''
        serializer_class = UserRegSerializer
        queryset = User.objects.all()
        authentication_classes = (JSONWebTokenAuthentication, authentication.SessionAuthentication)
    
        def create(self, request, *args, **kwargs):
            serializer = self.get_serializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            user = self.perform_create(serializer)
            re_dict = serializer.data
            payload = jwt_payload_handler(user)
            re_dict["token"] = jwt_encode_handler(payload)
            re_dict["name"] = user.name if user.name else user.username
    
            headers = self.get_success_headers(serializer.data)
    
            return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)
    
        #这里需要动态权限配置
        #1.用户注册的时候不应该有权限限制
        #2.当想获取用户详情信息的时候,必须登录才行
        def get_permissions(self):
            if self.action == "retrieve":
                return [permissions.IsAuthenticated()]
            elif self.action == "create":
                return []
    
            return []
    
        #这里需要动态选择用哪个序列化方式
        #1.UserRegSerializer(用户注册),只返回username和mobile,会员中心页面需要显示更多字段,所以要创建一个UserDetailSerializer
        #2.问题又来了,如果注册的使用userdetailSerializer,又会导致验证失败,所以需要动态的使用serializer
        def get_serializer_class(self):
            if self.action == "retrieve":
                return UserDetailSerializer
            elif self.action == "create":
                return UserRegSerializer
    
            return UserDetailSerializer

          # 因为继承了RetrieveModelMixin获取用户详细信息,那么在点进去查看用户详细信息时,
          # 需要传递一个id,这是固定格式(user/id),解决办法有两个,一个是在重载的create()
          # 中把用户id传进去。另一个用法就是调用RetrieveModelMixin的get_object方法,返回
          # self.request.user,这个的意思就是,无论用户后面跟的id是什么,只返回用户,这样我们
          # 就可以随便传个id给用户了,这样就不会报错。

        def get_object(self):
            return self.request.user

          # 这里的重载,是为了获取返回的用户对象。(serializer中的model=User)
          # 为上面的 user = self.perform_create(serializer)服务

    def perform_create(self, serializer):
            return serializer.save()

    主要添加的内容:

    • 继承mixins.RetrieveModelMixin   -->>获取用户信息
    • 重写get_object                              -->>获取登录的用户
    • get_permissions                           -->>动态权限分配
    • get_serializer_class                     -->>动态序列化分

    用户个人信息修改

    只需要多添加一个继承mixins.UpdateModelMixin就可以了

    class UserViewset(CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,viewsets.GenericViewSet):

     3、用户收藏

    (1)用户收藏商品详情

    user_operation/serializer.py中添加

    class UserFavDetailSerializer(serializers.ModelSerializer):
        '''
        用户收藏详情
        '''
        # 通过商品id获取收藏的商品,需要嵌套商品的序列化
        # 表示要显示的商品的信息内容,可以自己定义GoodsSerializer()中fields的内容
        goods = GoodsSerializer()
        class Meta:
            model = UserFav
            # "goods"表示收藏的商品id,"id"表示收藏记录的id
            fields = ("goods", "id")

    (2)user_operation/views.py

    动态设置serializer,道理跟我们前面说到的原理一样

    #动态选择serializer
        def get_serializer_class(self):
            if self.action == "list":
                return UserFavDetailSerializer
            elif self.action == "create":
                return UserFavSerializer
            return UserFavSerializer
    # user_operaton/views.py
    
    from rest_framework import viewsets
    from rest_framework import mixins
    from .models import UserFav
    from .serializers import UserFavSerializer,UserFavDetailSerializer
    from rest_framework.permissions import IsAuthenticated
    from utils.permissions import IsOwnerOrReadOnly
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from rest_framework.authentication import SessionAuthentication
    
    class UserFavViewset(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin):
        '''
        用户收藏
        '''
        #permission是用来做权限判断的
        # IsAuthenticated:必须登录用户;IsOwnerOrReadOnly:必须是当前登录的用户
        permission_classes = (IsAuthenticated,IsOwnerOrReadOnly)
        #auth使用来做用户认证的
        authentication_classes = (JSONWebTokenAuthentication,SessionAuthentication)
        #搜索的字段
        lookup_field = 'goods_id'
    
        #动态选择serializer
        def get_serializer_class(self):
            if self.action == "list":
                return UserFavDetailSerializer
            elif self.action == "create":
                return UserFavSerializer
            return UserFavSerializer
    
        def get_queryset(self):
            #只能查看当前登录用户的收藏,不会获取所有用户的收藏
            return UserFav.objects.filter(user=self.request.user)
    
    serializer.py
    View Code

     4、用户留言功能

    (1)user_operation/serializers.py

    class LeavingMessageSerializer(serializers.ModelSerializer):
        '''
        用户留言
        '''
        # 获取当前登录的用户
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()
        )
        #read_only:只返回,post时候可以不用提交,format:格式化输出
        # 不加read_only,我们在添加留言的时候,时间要自己加上去
        add_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M')
        class Meta:
            model = UserLeavingMessage
            fields = ("user", "message_type", "subject", "message", "file", "id" ,"add_time")

    (2)user_operation/views.py

    class LeavingMessageViewset(mixins.ListModelMixin, mixins.DestroyModelMixin, mixins.CreateModelMixin,
                                viewsets.GenericViewSet):
        """
        list:
            获取用户留言
        create:
            添加留言
        delete:
            删除留言功能
        """
    
        permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
        authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
        serializer_class = LeavingMessageSerializer
    
        # 只能看到自己的留言
        def get_queryset(self):
            return UserLeavingMessage.objects.filter(user=self.request.user)

    (3)配置url

    # 配置用户留言的url
    router.register(r'messages', LeavingMessageViewset, base_name="messages")

    5、用户收获地址

    (1)user_operation/serializers.py

    class AddressSerializer(serializers.ModelSerializer):
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()
        )
        add_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M')
    
        class Meta:
            model = UserAddress
            fields = ("id", "user", "province", "city", "district", "address", "signer_name", "add_time", "signer_mobile")

    (2)user_operation/views.py

    如果要实现增删改查功能,只要继承ModelViewSet就可以了

    class AddressViewset(viewsets.ModelViewSet):
        """
        收货地址管理
        list:
            获取收货地址
        create:
            添加收货地址
        update:
            更新收货地址
        delete:
            删除收货地址
        """
        permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
        authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
        serializer_class = AddressSerializer
    
        def get_queryset(self):
            return UserAddress.objects.filter(user=self.request.user)

    (3)配置url

    # 配置收货地址
    router.register(r'address',AddressViewset , base_name="address")
  • 相关阅读:
    【DFS】XIII Open Championship of Y.Kupala Grodno SU Grodno, Saturday, April 29, 2017 Problem D. Divisibility Game
    【二分】【三分】【计算几何】XIII Open Championship of Y.Kupala Grodno SU Grodno, Saturday, April 29, 2017 Problem L. Lines and Polygon
    【线段树】XIII Open Championship of Y.Kupala Grodno SU Grodno, Saturday, April 29, 2017 Problem J. Jedi Training
    【贪心】【后缀自动机】XIII Open Championship of Y.Kupala Grodno SU Grodno, Saturday, April 29, 2017 Problem E. Enter the Word
    【转载】随机生成k个范围为1-n的随机数,其中有多少个不同的随机数?
    【推导】【贪心】XVII Open Cup named after E.V. Pankratiev Stage 4: Grand Prix of SPb, Sunday, Octorber 9, 2016 Problem H. Path or Coloring
    【枚举】XVII Open Cup named after E.V. Pankratiev Stage 4: Grand Prix of SPb, Sunday, Octorber 9, 2016 Problem D. Cutting Potatoes
    【找规律】【递归】XVII Open Cup named after E.V. Pankratiev Stage 4: Grand Prix of SPb, Sunday, Octorber 9, 2016 Problem F. Doubling
    【贪心】Codeforces Round #436 (Div. 2) D. Make a Permutation!
    【计算几何】【圆反演】计蒜客17314 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 G. Finding the Radius for an Inserted Circle
  • 原文地址:https://www.cnblogs.com/linyuhong/p/9942090.html
Copyright © 2011-2022 走看看