Django 2.0.2 (Django-rest-framework) and the front-end and back-end separated mall website developed by front-end vue
Online demo address: http://vueshop.mtianyan.cn/
github source code address: https://github.com/mtianyan/VueDjangoFrameWorkShop
This section: Order Management Interface
Order Management Interface
First, understand the relationship between shopping carts and orders.
Now we're doing the simplest thing we can do is to settle all the items in the shopping cart together.
There is an order_sn in the orderInfo model that cannot be empty.
Click to settle and generate an order for it. Then let the user pay for the page. If you use the create mixin of viewset China. These fields are validated. But it's impossible for users to post order_sn.
Then we set the field in the model to be null, so that we can validate the field without any problem.
# unique Order Number unique order_sn = models.CharField(max_length=30, null=True, blank=True, unique=True, verbose_name="Order number") # In case the user doesn't pay half of the payment pay_status = models.CharField(choices=ORDER_STATUS, default="paying", max_length=30, verbose_name="Order status")
trade_no is Alipay's return number for us.
Why not point to a foreign key and save the value?
Because the user may change the address, the address is deleted, but the order associated with the address as historical data should not be changed.
orderInfo has only basic information, but related to the order is the commodity information of the order.
So we designed OrderGoods to store the goods we ordered.
Add an OrderViewSet to implement the order interface
class OrderViewset(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet):
Why use generic Viewset instead of ModelViewset? Orders are generally not allowed to be modified.
No update, this mixin
List shows the list of orders, create new orders, and Destroy Model Mixin deletes orders.
class OrderViewset(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet): """ //Order management list: //Obtaining personal orders delete: //Delete order create: //New order """ permission_classes = (IsAuthenticated, IsOwnerOrReadOnly) authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication) serializer_class = OrderSerializer def get_queryset(self): return OrderInfo.objects.filter(user=self.request.user)
Add an OrderSerializer to Serilizers.py
class OrderSerializer(serializers.ModelSerializer): class Meta: model = OrderInfo fields = "__all__"
When submitting an order, each item will not be submitted again, because the logic is a relatively simple business logic that empties the shopping cart directly.
- Add the data in the shopping cart to OrderGoods.
- Empty shopping cart data
It took two more steps to create the order.
We can write in perform_create, and the actual default call is Serializer's save method.
def perform_create(self, serializer): order = serializer.save()
The order number before save is required, in Serilizer.
def generate_order_sn(self): # Current time + userid + random number 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
The time series plus user id plus random string. 10-99 generates our order number. Note the different ways to retrieve the current user in Serilizer and view.
def validate(self, attrs): attrs["order_sn"] = self.generate_order_sn() return attrs
Once done in validate, save can be called directly in view
def perform_create(self, serializer): order = serializer.save() # Get the goods in the user's shopping cart 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
Now we have the order.
Get the goods in the shopping cart, then go through the for loop to generate the items of the order and save them.
Empty the shopping cart and return order
Then configure a url for our orderviewset
# Order-related url router.register(r'orders', OrderViewset, base_name="orders")
At this point, the user is listed, and we should select the current default user and hide the selection box.
In OrderSerializer
user = serializers.HiddenField( default=serializers.CurrentUserDefault() )
The status of the order should not be a value that the user can submit. So add readonly for order status
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)
Similarly available are transaction number, order number, payment time, etc.
When deleting an order, we need the id returned when the order is generated. When deleting an order, we want to delete the items in the order together. So will we test it and delete it together?
Both orderinfo and ordergoods were deleted.
vue personal Center Order Interface debugging
Related interfaces are located at
//Get order export const getOrders = () => { return axios.get(`${host}/orders/`) } //Delete order export const delOrder = orderId => { return axios.delete(`${host}/orders/`+orderId+'/') } //Add order export const createOrder = params => {return axios.post(`${host}/orders/`, params)} //Obtain order details export const getOrderDetail = orderId => {return axios.get(`${host}/orders/`+orderId+'/')}
Change the host of these four interfaces to localhost.
First is the settlement page. There is no specific information about the goods in the order interface.
trade/views.py for dynamic Serializer selection
def get_serializer_class(self): if self.action == "retrieve": return OrderDetailSerializer return OrderSerializer
trade/serializers.py New OrderDetailSerializer Class
class OrderDetailSerializer(serializers.ModelSerializer): goods = OrderGoodsSerialzier(many=True) class Meta: model = OrderInfo fields = "__all__"
The goods field is nested with an OrderGoods Serializer
trade/serializers.py Add OrderGoods Serialzier:
class OrderGoodsSerialzier(serializers.ModelSerializer): goods = GoodsSerializer(many=False) class Meta: model = OrderGoods fields = "__all__"
Order Goods Serializer is used for serialization of goods details.
class OrderGoods(models.Model): """ Details of the goods in the order """ # An order corresponds to more than one item, so add foreign keys order = models.ForeignKey(OrderInfo, on_delete=models.CASCADE, verbose_name= "order information", related_name="goods")
The order is associated with the item in the order.
The first goods is actually a foreign key relationship, and the embedded goods are our product details.
When the order status is not paid, the button that Alipay will pay will be displayed.
Order logic in vue
The key step in mapping the data to the shopping cart is to submit for settlement.
<p class="sumup"><a class="btn" @click="balanceCount">Settlement</a></p>
Clicking to settle accounts calls the balanceCount method.
balanceCount () { // Settlement if(this.addrInfo.length==0){ alert("Please choose the receiving address.") }else{ createOrder( { post_script:this.post_script, address:this.address, signer_name:this.signer_name, singer_mobile:this.signer_mobile, order_mount:this.totalPrice } ).then((response)=> { alert('Order Creation Success') window.location.href=response.data.alipay_url; }).catch(function (error) { console.log(error); }); } },
- First of all, judge whether the acceptance qualifications have been selected.
If you have already selected, create the order.
//Add order export const createOrder = params => {return axios.post(`${local_host}/orders/`, params)}
Pass parameters to the order interface (post_script message), and if the response is successful, the pop-up order is created successfully. And automatically jump to the Alipay_url provided in the response data.
How to Choose the Receiving Address
selectAddr (id) { //Selection of distribution address this.addressActive = id; var cur_address = '' var cur_name = '' var cur_mobile = '' this.addrInfo.forEach(function(addrItem) { if(addrItem.id == id){ cur_address = addrItem.province+addrItem.city+addrItem.district+addrItem.address cur_name = addrItem.signer_name cur_mobile = addrItem.signer_mobile } }); this.address = cur_address this.signer_mobile = cur_mobile this.signer_name = cur_name },
The status value is updated when the receiving address is selected.
My subscription unit is order.vue in member
It's actually calling getorder()
created () { this.getOrder(); }, getOrder () { getOrders().then((response)=> { this.orders = response.data; }).catch(function (error) { console.log(error); }); },
The getorders interface is
//Get order export const getOrders = () => { return axios.get(`${local_host}/orders/`) }
The logical call to order detail is our getorderdetail, which returns all goods of the order.
created () { this.orderId = this.$route.params.orderId; this.getOrderInfo(); this.getReceiveByOrderId(); },
getOrderInfo () { //Get order information getOrderDetail(this.orderId).then((response)=> { this.orderInfo = response.data; var totalPrice = 0 response.data.goods.forEach(function(entry) { totalPrice += entry.goods_num*entry.goods.shop_price }); this.totalPrice = totalPrice }).catch(function (error) { console.log(error); }); },
Orderinfo does some data mapping.