17-vue Django restful framework to create fresh supermarket-order management interface

Keywords: Python axios Vue Django

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")
mark

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.

mark

The first goods is actually a foreign key relationship, and the embedded goods are our product details.

mark

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.

Posted by hubfub on Tue, 11 Dec 2018 06:18:07 -0800