1. 程式人生 > >DRF 商城項目 - 個人中心(收藏, 留言, 收貨地址)

DRF 商城項目 - 個人中心(收藏, 留言, 收貨地址)

eth 信息 當前 個人中心 delet 源碼 cati 方式 self

用戶個人中心

retrieve 方式添加

用戶中心的數據來源是對單一用戶的詳細數據請求, 因此需要在原有基礎上加上對 retrieve 的處理

 mixins.RetrieveModelMixin

用戶 id 傳遞

同時因為對單一用戶的請求需要指明用戶id, 有兩種方式可以傳遞

第一種 直接在數據裏面提供當前用戶 id

第二種 重寫 get_object 獲取當前用戶

# 因為要涉及到 個人中心的操作需要傳遞過去 用戶的 id, 重寫 get_object 來實現
    def get_object(self):
        return self.request.user

權限分離

用戶中心必須指定當前用戶只能訪問自己, 因此需要對是否登錄進行驗證

但是當前視圖的其他類型請求比如 create 的註冊則不需要進行驗證, 因此 permission_classes 無法滿足需求

源碼剖析

在繼承了 ViewSetMixin 之後內部的 initialize_request 方面裏面的 提供了 .actionrequest 中可以對請求類型進行分離

技術分享圖片

同時 APIView 內部的 get_permissions 方法負責提取認證類型, 因此重寫此方法即可完成

技術分享圖片

此為 源碼, 可見是直接使用一個列表表達式來獲取當前視圖的 permission_classes

裏面的所有認證方式

技術分享圖片

實現重寫

基於我們自己的需求進行重寫, 利用 action 進行分流

註意其他未設置的最後一定要返回空

    # permission_classes = (permissions.IsAuthenticated, )  # 因為根據類型的不同權限的認證也不同, 不能再統一設置了
    def get_permissions(self):
        if self.action == "retrieve":
            return [permissions.IsAuthenticated()]
        elif self.action == "
create": return [] return []

序列化組件分離

創建組件

之前設置的序列化組件是為了註冊用的, 只采集了註冊相關的字段, 無法滿足用戶中心的其他字段處理

因此需要重新設置一個用戶詳情的 序列化組件

# 用戶詳情信息序列化類
class UserDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ("name", "gender", "birthday", "email", "mobile")

源碼剖析

同樣是基於對 action 的方法進行分流, 對於 action 的位置在 權限分流的部分有圖,

GenericAPIView 中存在 get_serializer_class 方法, 用於獲取當前視圖中的 序列化組件

技術分享圖片

實現重寫

基於 action 進行分流, 然後進行對 get_serializer_class 進行重寫

實現方式類似於 權限的分流

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

個人收藏

整體邏輯類似於 個人中心,

收藏 ----> 註冊

收藏詳情 -----> 用戶信息

序列化組件

收藏詳情需要用到收藏的商品全部內容, 序列化的時候需要進行組件的嵌套, 將商品序列化組件嵌進去

# 收藏詳情
class UserFavDetailSerializer(serializers.ModelSerializer):
    goods = GoodsSerializer(many=True)

    class Meta:
        model = UserFav
        fields = ("goods", "id")

收藏的時候需要註意設置一個聯合唯一索引, 在序列化中設置後或者 models 中設置皆可

# 用戶收藏
class UserFavSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )

    class Meta:
        model = UserFav
        # 聯合唯一可以在 model 中創建的時候進行操作, 通過 ModelSerializer 自然會幫你完成驗證
        # 也可以在這裏完成, 註意是在 Meta 中進行設置, 因為這是多字段的處理
        validators = [
            UniqueTogetherValidator(
                queryset=UserFav.objects.all(),
                fields=(user, goods),
                message="已經收藏過了"
            )
        ]
        fields = ("user", "goods", "id")  # 刪除的需要因此加上 id, 這樣方便刪除操作

視圖

整體邏輯類似於個人中心

依舊是 分流處理序列化組件, 因為收藏功能的全部請求都需要在用戶登錄下查看

因此不需認證分流

# 用戶收藏功能
class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin,
                     mixins.DestroyModelMixin, viewsets.GenericViewSet):
    """
    list:
        獲取用戶收藏列表
    retrieve:
        判斷某個商品是否已經收藏
    create:
        收藏商品
    destroy:
        取消商品收藏
    """
    # queryset = UserFav.objects.all() # 只能看自己的收藏記錄
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    serializer_class = UserFavSerializer
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    lookup_field = "goods_id"

    # 分流處理 序列化組件
    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)

用戶留言

基本上所用的字段什麽的在上面都有用過了

序列化組件

需要註意的是留言時間的格式, 以及只讀屬性

註意 user 字段的傳入應該是默認的當前用戶, 且此字段可以設置成隱藏

# 用戶留言
class LeavingMessageSerializer(serializers.ModelSerializer):
    # 設置隱藏字段
    user = serializers.HiddenField(
        # 默認值為當前用戶
        default=serializers.CurrentUserDefault()
    )
    # 留言的時間不能自己指定, 應該是系統自動根據當前的時間, 因此設置為只讀
    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")

視圖

# 用戶留言
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)

用戶收貨地址

基本上和留言一樣了.

序列化組件

# 收貨地址
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")

視圖

# 收貨地址
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)

DRF 商城項目 - 個人中心(收藏, 留言, 收貨地址)