16-vue Django restful framework to create fresh supermarket-shopping cart function realization

Keywords: Python Django REST axios

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: Shopping cart function

Functional Requirements Analysis of Shopping Cart and Its Implementation by Joining in Shopping Cart

Click on Add to the shopping cart for details. The shopping cart in the upper right corner will add new items.

This is the data from the background, Click to the settlement page. It's the goods, how many pieces and the total price.

The distribution address is displayed.

Click to add a product and the quantity will change.

  • To add goods many times is to add one to the number of goods.

It has been recorded, and the most common practice is to add one. If not, add a new record.

Click add one and subtract one. Do you make a single interface or update the number directly?

There are many ways to accomplish the function, which way to implement it is related to the complexity of the background.

Get the list page, create, update, delete.

Notice that the return in shopping cart is

    def __str__(self):
        return "%s(%d)".format(self.goods.name, self.nums)

Complete our viewset.

from rest_framework import viewsets

class ShoppingCartViewset(viewsets.ModelViewSet):
    """
    Shopping cart function
    list:
        Get shopping cart details
    create: 
        Add to cart
    delete: 
        Delete shopping records
    """
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)

We're going to prepare a complete Serializer for our viewset and build a new Serializers.py

Inherit Serializer instead of model Serializer. Because Serializer is flexible

unique_together in Model has also been used in the collection of goods. Collections are allowed only once in a collection, and what we want now is the number of updates when adding again.

        unique_together = ("user", "goods")

If we inherit the model Serializer. Then it verifies is_vaild in the create method. So we can't get into our own repeated plus one operation.

class ShopCartSerializer(serializers.Serializer):
    # Serializer itself is the best because it is the most flexible.
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    nums = serializers.IntegerField(required=True, label="Number",min_value=1,
                                    error_messages={
                                        "min_value":"The quantity of goods should not be less than 1",
                                        "required": "Please choose the quantity you want to buy."
                                    })
    goods = serializers.PrimaryKeyRelatedField(required=True, queryset=Goods.objects.all())

Goods is a foreign key field in Serializer. Query out all the values in goods object.

http://www.django-rest-framework.org/api-guide/fields/

You can see the fields that Serializer naturally provides us with

These relational types, such as foreign keys, are put in

http://www.django-rest-framework.org/api-guide/relations/

modelSerializer is used in documents. So there's no need to specify queryset, and we're using Serializer.
So let's specify queryset

Serializer does not provide save, so let's rewrite the create method

The validated_data passed in by the create method is the data that has passed through the validate.

And initial_data is the original value that has not been validate d. We need to do type conversion and so on.

  • Users can be extracted directly from requests in view, but not directly from requests in Serializer.

From user = self. context ["request"].

 def create(self, validated_data):
        user = self.context["request"].user
        nums = validated_data["nums"]
        goods = validated_data["goods"]

        existed = ShoppingCart.objects.filter(user=user, goods=goods)

        if existed:
            existed = existed[0]
            existed.nums += nums
            existed.save()
        else:
            existed = ShoppingCart.objects.create(**validated_data)

        return existed

If it exists, take this object out, num+1, and save it.

  • If it does not exist, create a shoppingcart object based on validate data. Then return to the front end

Configure Serializer in viewset

    serializer_class = ShopCartSerializer
    def get_queryset(self):
        return ShoppingCart.objects.filter(user=self.request.user)

Shopping cart list page only retrieves the contents of its own shopping cart

Configuration-related URLs

# Receiving address
router.register(r'shopcarts', ShoppingCartViewset, base_name="shopcarts")

Modify the number of items in the shopping cart

Like collections, you want to pass goods_id instead of the ID of the relationship.

    lookup_field = "goods_id"

The default lookup_field is the id primary key of the model. This can be obtained through the commodity id.

mark

The number of updates is 5

Report errors:

NotImplementedError at /shopcarts/1/
`update()` must be implemented.

Personal information modification did not implement the update method, there is no problem. Now why do you want to implement the update method?

Serializer inherits from baseSerializer. But Serializer did not override the update method.

    def update(self, instance, validated_data):
        raise_errors_on_nested_writes('update', self, validated_data)
        info = model_meta.get_field_info(instance)

        # Simply set each attribute on the instance, and then save it.
        # Note that unlike `.create()` we don't need to treat many-to-many
        # relationships as being a special case. During updates we already
        # have an instance pk for the relationships to be associated with.
        for attr, value in validated_data.items():
            if attr in info.relations and info.relations[attr].to_many:
                field = getattr(instance, attr)
                field.set(value)
            else:
                setattr(instance, attr, value)
        instance.save()

        return instance

As shown in the code above, our modelSerializer implements the update method. So we can imitate the update method to implement the update in our Serializer.

So that's why we inherit model Serializer and don't need to implement update

    def update(self, instance, validated_data):
        # Modify the quantity of goods
        instance.nums = validated_data["nums"]
        instance.save()
        return instance

vue and shopping cart interface debugging

Before we can get the unit price and quantity of the goods, we need to get the details of the goods.

For example, the name of the commodity and the ID of the commodity. Pictures of merchandise.

We now have only goods'primary key id in Serilizer. Serializer needs to be set dynamically

This Serializer is a dynamic Serializer.

class ShopCartDetailSerializer(serializers.ModelSerializer):
    # A shopping cart relationship record corresponds to only one goods.
    goods = GoodsSerializer(many=False, read_only=True)
    class Meta:
        model = ShoppingCart
        fields = ("goods", "nums")

Then make dynamic Serializer selection in views


    def get_serializer_class(self):
        if self.action == 'list':
            return ShopCartDetailSerializer
        else:
            return ShopCartSerializer

The api.js file in the front-end project.

Implementation code:

//Getting shopping cart goods
export const getShopCarts = params => { return axios.get(`${host}/shopcarts/`) }
// Add merchandise to shopping cart
export const addShopCart = params => { return axios.post(`${host}/shopcarts/`, params) }
//Update shopping cart merchandise information
export const updateShopCart = (goodsId, params) => { return axios.patch(`${host}/shopcarts/`+goodsId+'/', params) }
//Delete a shopping record of an item
export const deleteShopCart = goodsId => { return axios.delete(`${host}/shopcarts/`+goodsId+'/') }

Change the host of the above four interfaces to localhost

Add Shopping Cart in Component src/views/product Detail/product Detail.vue

addShoppingCart () { //Add to cart
            addShopCart({
                goods: this.productId, // Commodity id
                nums: this.buyNum, // Purchase quantity
            }).then((response)=> {
                this.$refs.model.setShow();
                // Update store data
                this.$store.dispatch('setShopList');

            }).catch(function (error) {
                console.log(error);
            });

Add merchandise to background data interface

export const addShopCart = params => { return axios.post(`${local_host}/shopcarts/`, params) }

Pass goods, which is the id of the product. And the number of purchases.

If successful, our shopping cart will be updated.

export const setShopList = makeAction(types.SET_SHOPLIST);

The head section fetches the data:

    computed: {
        ...mapGetters({
          goods_list: 'goods_list',
          userInfo:'userInfo'
        })
    },

This data is displayed in the shopping cart in the head.

mark

for loop traversal displays the goods. The use of v-link allows you to skip over product details.

mark

Prices are all data from vuex, so dynamic data binding and updating will take place.

Adding the number of items to the settlement is a patch return operation

src/views/cart/cart.vue

    created () {
      // Request shopping cart merchandise
      getShopCarts().then((response)=> {
        console.log(response.data)
        // Update store data
        //this.goods_list = response.data;
        var totalPrice = 0
        this.goods.goods_list = response.data;
        response.data.forEach(function(entry) {
          totalPrice += entry.goods.shop_price*entry.nums
          console.log(entry.goods.shop_price);
        });

        this.goods.totalPrice = totalPrice
        this.totalPrice = totalPrice
      }).catch(function (error) {
      });
      this.getAllAddr ()

    },

When creating, call getShopCarts to fetch the shopping cart merchandise data

Calculating the total price, the total price is mapped to the page. The data from the back end will be sent to goods.

The for loop displays the fields with goods_list.

 reduceCartNum(index, id) { //Delete quantity
        if(this.goods.goods_list[index].nums<=1){
          this.deleteGoods(index, id)
        }else{
          updateShopCart(id,{
            nums: this.goods.goods_list[index].nums-1
          }).then((response)=> {
            this.goods.goods_list[index].nums = this.goods.goods_list[index].nums - 1;
            // Update store data
            this.$store.dispatch('setShopList');
            //Renewal price
            this.setTotalPrice();

          }).catch(function (error) {
            console.log(error);
          });
        }

Continuous reduction, if less than 1, then call delete goods to delete this product.

Update vuex if you succeed. Because this data is also used in the global head. Only by modifying the global data of vuex1, can we keep our data consistent.

mark

Filling in the distribution address comes from addrInfo

getAllAddr () { //Get all distribution addresses
        getAddress().then((response)=> {
          this.addrInfo = response.data;
        }).catch(function (error) {
          console.log(error);
        });
      },

Gets the configuration before getAddress().

By choosing the address, the shopping cart merchandise plus payment method can be completely turned into an order.

Posted by leetcrew on Sun, 06 Jan 2019 22:27:10 -0800