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.
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.
for loop traversal displays the goods. The use of v-link allows you to skip over product details.
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.
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.