【Django REST framework電商專案筆記】第10章 購物車, 訂單和支付寶支付功能(中)
訂單管理介面實現
首先理解一下購物車和訂單之間的關係。 我們現在是做了一種最簡單的實現就是把購物車中所有商品進行一起的結算 orderInfo model 裡面有一個order_sn是不能為空的。
點選去結算之後為它生成一個訂單。然後讓使用者去支付頁面進行支付。 如果用到viewset中的create mixin。會對這些欄位進行驗證。 但是使用者是不可能post order_sn過來的。
那我們在model中設定該欄位可以為空,這樣驗證欄位時就沒有問題了。
為什麼不指向一個外來鍵而是將值存起來呢? 因為使用者有可能地址變動,將該地址刪除了,但是地址相關聯的訂單作為歷史資料不應該被改變。
orderInfo 只有基本的資訊,但是與訂單相關的還有訂單的商品資訊。 所以我們設計了 OrderGoods 來儲存訂單的商品。 新增一個OrderViewSet來實現訂單介面
class OrderViewSet(mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.CreateModelMixin,
mixins.DestroyModelMixin,
viewsets.GenericViewSet):
"""
訂單管理
list: 列出個人訂單
create: 添加個人訂單
delete: 刪除個人訂單
"""
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
serializer_class = OrderSerializer
def get_queryset(self):
return OrderInfo.objects.filter(user=self.request.user)
為什麼使用genericViewset,而不是ModelViewset。因為訂單一般是不允許被修改的。沒有update這個mixin
在 Serializers.py 中新增一個 OrderSerializer
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = OrderInfo
fields = "__all__"
提交訂單的時候不會再提交每個商品,因為邏輯是一種比較簡單的業務邏輯,直接清空購物車
將購物車中的資料新增到 OrderGoods 中。 清空購物車資料
它在create訂單的時候還多了兩步 我們可以在 perform_create 中寫,實際預設呼叫的是 Serializer 的save方法 views/OrderViewSet
def perform_create(self, serializer):
order = serializer.save()
save之前訂單號是必須要有的,在Serializer中。
def generate_order_sn(self):
# 當前時間 + user.id + 隨機數
from random import Random
random_ins = Random()
order_sn = "{time_str}{userid}{ranstr}".format(time_str=time.strftime("%Y%m%d%H%M%S"),
userid=self.context["request"].user.id,
ranstr=random_ins.randint(10, 99))
return order_sn
由時間串加使用者id加隨機字串。10-99生成我們的訂單編號 注意在 Serializer 中和 view 中取當前使用者的不同方法。
def validate(self, attrs):
attrs["order_sn"] = self.generate_order_sn()
return attrs
在 validate 中完成之後,在 view 中就可以直接呼叫 save() 方法了
def perform_create(self, serializer):
order = serializer.save()
# 獲取使用者購物車的商品
shop_carts = ShoppingCart.objects.filter(user=self.request.user)
for shop_cart in shop_carts:
order_goods = OrderGoods()
order_goods.goods = shop_cart.goods
order_goods.goods_num = shop_cart.nums
order_goods.order = order
order_goods.save()
shop_cart.delete()
return order
現在我們就拿到 order 了
獲取到購物車裡面的商品,然後進行 for 迴圈的遍歷生成訂單的商品專案並儲存 清空購物車然後 return order
配置訂單的URL
# 配置訂單相關的路由
router.register(r'orders', OrderViewSet, base_name="orders")
訂單的狀態不應該是使用者可以提交的值。所以為訂單狀態新增 read_only
pay_status = serializers.CharField(read_only=True)
trade_no = serializers.CharField(read_only=True)
order_sn = serializers.CharField(read_only=True)
pay_time = serializers.DateTimeField(read_only=True)
同理可得的有交易號,訂單號,支付時間等。
刪除訂單的時候,我們需要生成訂單時返回的id。刪除訂單時我們將訂單中的商品項一起刪除掉。
vue訂單介面除錯
首先是結算頁面。訂單的介面中沒有商品的具體資訊。
trade/views.py進行動態的Serializer的選擇
def get_serializer_class(self):
if self.action == "retrieve":
return OrderDetailSerializer
return OrderSerializer
trade/serializers.py新建OrderDetailSerializer類
class OrderDetailSerializer(serializers.ModelSerializer):
goods = OrderGoodsSerializer(many=True)
class Meta:
model = OrderInfo
fields = "__all__"
其中的goods欄位巢狀一個OrderGoodsSerializer trade/serializers.py新增OrderGoodsSerialzier:
class OrderGoodsSerializer(serializers.ModelSerializer):
goods = GoodsSerializer(many=False)
class Meta:
model = OrderGoods
fields = "__all__"
orderGoodsSerializer用於goods詳情的序列化。
訂單與訂單內的商品項是通過order進行關聯的。 第一個goods實際上是外來鍵關係,內層巢狀的goods才是我們的商品詳情 訂單狀態是未支付的時候會顯示支付寶支付的按鈕。