DRF 商城項目 - 個人中心(收藏, 留言, 收貨地址)
用戶個人中心
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 方面裏面的 提供了 .action 在 request 中可以對請求類型進行分離
同時 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 商城項目 - 個人中心(收藏, 留言, 收貨地址)