1. 程式人生 > >Django REST framework+Vue 打造生鮮超市(五)

Django REST framework+Vue 打造生鮮超市(五)

.com his gem serial http return cati 頁碼 erro

六、商品類別數據展示

6.1. 商品類別數據接口

(1)商品分類有兩個接口:

一種是全部分類:一級二級三級

技術分享圖片

一種是某一類的分類以及商品詳細信息:

技術分享圖片

開始寫商品分類的接口

(2)序列化

給分類添加三級分類的serializer

goods/serializers.py

技術分享圖片
from rest_framework import serializers
from .models import Goods,GoodsCategory


class CategorySerializer3(serializers.ModelSerializer):
    ‘‘‘三級分類‘‘‘
    class Meta:
        model = GoodsCategory
        fields = "__all__"


class CategorySerializer2(serializers.ModelSerializer):
    ‘‘‘
    二級分類
    ‘‘‘
    #在parent_category字段中定義的related_name="sub_cat" 
    sub_cat = CategorySerializer3(many=True)
    class Meta:
        model = GoodsCategory
        fields = "__all__"


class CategorySerializer(serializers.ModelSerializer):
    """
    商品一級類別序列化
    """
    sub_cat = CategorySerializer2(many=True)
    class Meta:
        model = GoodsCategory
        fields = "__all__"
技術分享圖片

(3)views.py

技術分享圖片
class CategoryViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    ‘‘‘
    list:
        商品分類列表數據
    ‘‘‘

    queryset = GoodsCategory.objects.filter(category_type=1)
    serializer_class = CategorySerializer
技術分享圖片

說明:

  • 註釋的內容,在後面生成drf文檔的時候會顯示出來,所有要寫清楚
  • 要想獲取某一個商品的詳情的時候,繼承 mixins.RetrieveModelMixin 就可以了

(4)url配置

# 配置Category的url
router.register(r‘categorys‘, CategoryViewSet, base_name="categorys")

技術分享圖片

6.2.vue展示商品分類數據

接口相關代碼都放在src/api/api.js裏面,調試接口的時候我們首先需要新建一個自己的host,然後替換要調試的host

(1)新建local_host

let local_host = ‘http://127.0.0.1:8000‘

(2)替換商品類別默認的host

技術分享圖片
//獲取商品類別信息
export const getCategory = params => {
  if(‘id‘ in params){
    return axios.get(`${local_host}/categorys/`+params.id+‘/‘);
  }
  else {
    return axios.get(`${local_host}/categorys/`, params);
  }
};
技術分享圖片

這個時候訪問 http://127.0.0.1:8080/#/app/home/index

發現不顯示商品分類了,是因為這涉及到了跨域問題,接下來就解決跨域的問題

技術分享圖片

drf跨域問題

後端服務器解決跨域問題的方法

(1)安裝模塊

pip install django-cors-headers

django-cors-headers 使用說明:https://github.com/ottoyiu/django-cors-headers

(2)添加到INSTALL_APPS中

INSTALLED_APPS = (
    ...
    ‘coreschema‘,
 ... )

(3)添加中間件

下面添加中間件的說明:

CorsMiddleware should be placed as high as possible, especially before any middleware that can generate responses such as Django‘s CommonMiddleware or Whitenoise‘s WhiteNoiseMiddleware. If it is not before, it will not be able to add the CORS headers to these responses.

Also if you are using CORS_REPLACE_HTTPS_REFERER it should be placed before Django‘s CsrfViewMiddleware (see more below).

意思就是 要放的盡可能靠前,必須在CsrfViewMiddleware之前。我們直接放在第一個位置就好了

技術分享圖片
MIDDLEWARE = [
    ‘corsheaders.middleware.CorsMiddleware‘,
    ‘django.middleware.security.SecurityMiddleware‘,
    ‘django.contrib.sessions.middleware.SessionMiddleware‘,
    ‘django.middleware.common.CommonMiddleware‘,
    ‘django.middleware.csrf.CsrfViewMiddleware‘,
    ‘django.contrib.auth.middleware.AuthenticationMiddleware‘,
    ‘django.contrib.messages.middleware.MessageMiddleware‘,
    ‘django.middleware.clickjacking.XFrameOptionsMiddleware‘,
]
技術分享圖片

(4)設置為True

CORS_ORIGIN_ALLOW_ALL = True

現在再訪問 http://127.0.0.1:8080/#/app/home/index 數據就可以填充進來了

技術分享圖片

在一級分類中設置為True

技術分享圖片

技術分享圖片

6.3.vue展示商品列表頁數據

商品列表頁會判斷我們是serach還是getGoods

技術分享圖片
getListData() {
                if(this.pageType==‘search‘){
                  getGoods({
                    search: this.searchWord, //搜索關鍵詞
                  }).then((response)=> {
                    this.listData = response.data.results;
                    this.proNum = response.data.count;
                  }).catch(function (error) {
                    console.log(error);
                  });
                }else {
                  getGoods({
                    page: this.curPage, //當前頁碼
                    top_category: this.top_category, //商品類型
                    ordering: this.ordering, //排序類型
                    pricemin: this.pricemin, //價格最低 默認為‘’ 即為不選價格區間
                    pricemax: this.pricemax // 價格最高 默認為‘’
                  }).then((response)=> {

                    this.listData = response.data.results;
                    this.proNum = response.data.count;
                  }).catch(function (error) {
                    console.log(error);
                  });
                }

            },
技術分享圖片

說明:

(1)page分頁

page_size數量與前端一致

頁碼參數與起前端一致"page"

技術分享圖片
class GoodsPagination(PageNumberPagination):
    ‘‘‘
    商品列表自定義分頁
    ‘‘‘
    #默認每頁顯示的個數
    page_size = 12
    #可以動態改變每頁顯示的個數
    page_size_query_param = ‘page_size‘
    #頁碼參數
    page_query_param = ‘page‘
    #最多能顯示多少頁
    max_page_size = 100
技術分享圖片

(2)過濾

top_category是商品的一級分類,需要傳入參數:一級分類的id

pricemin和pricemax與前端保持一致

獲取一級分類下的所有商品

技術分享圖片
# goods/filters.py

import django_filters

from .models import Goods
from django.db.models import Q

class GoodsFilter(django_filters.rest_framework.FilterSet):
    ‘‘‘
    商品過濾的類
    ‘‘‘
    #兩個參數,name是要過濾的字段,lookup是執行的行為,‘小與等於本店價格’
    pricemin = django_filters.NumberFilter(name="shop_price", lookup_expr=‘gte‘)
    pricemax = django_filters.NumberFilter(name="shop_price", lookup_expr=‘lte‘)
    top_category = django_filters.NumberFilter(name="category", method=‘top_category_filter‘)

    def top_category_filter(self, queryset, name, value):
        # 不管當前點擊的是一級分類二級分類還是三級分類,都能找到。
        return queryset.filter(Q(category_id=value) | Q(category__parent_category_id=value) | Q(
            category__parent_category__parent_category_id=value))

    class Meta:
        model = Goods
        fields = [‘pricemin‘, ‘pricemax‘]
技術分享圖片

(3)排序

GoodsListViewSet中ording與前端要一致

技術分享圖片

   #排序
    ordering_fields = (‘sold_num‘, ‘shop_price‘)

(4)替換為local_host

//獲取商品列表
export const getGoods = params => { return axios.get(`${local_host}/goods/`, { params: params }) }

(5)搜索

   #搜索
    search_fields = (‘name‘, ‘goods_brief‘, ‘goods_desc‘)

現在就可以從後臺獲取商品的數據了,主要功能

  • 分類過濾
  • 價格區間過濾
  • 顯示商品數量
  • 分頁
  • 搜索

技術分享圖片

所有代碼:

按 Ctrl+C 復制

# MxShop/urls.py
__author__ = ‘derek‘


from django.urls import path,include,re_path
import xadmin
from django.views.static import serve
from MxShop.settings import MEDIA_ROOT
# from goods.view_base import GoodsListView

from rest_framework.documentation import include_docs_urls
from goods.views import GoodsListViewSet,CategoryViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()

#配置goods的url
router.register(r‘goods‘, GoodsListViewSet,base_name=‘goods‘)
# 配置Category的url
router.register(r‘categorys‘, CategoryViewSet, base_name="categorys")


urlpatterns = [
path(‘xadmin/‘, xadmin.site.urls),
path(‘api-auth/‘,include(‘rest_framework.urls‘)),
path(‘ueditor/‘,include(‘DjangoUeditor.urls‘ )),
#文件
path(‘media/<path:path>‘,serve,{‘document_root‘:MEDIA_ROOT}),
#drf文檔,title自定義
path(‘docs‘,include_docs_urls(title=‘仙劍奇俠傳‘)),
#商品列表頁
re_path(‘^‘, include(router.urls)),
]

MxShop/urls.py

代碼 按 Ctrl+C 復制代碼

# goods/filters.py

import django_filters

from .models import Goods
from django.db.models import Q

class GoodsFilter(django_filters.rest_framework.FilterSet):
‘‘‘
商品過濾的類
‘‘‘
#兩個參數,name是要過濾的字段,lookup是執行的行為,‘小與等於本店價格’
pricemin = django_filters.NumberFilter(name="shop_price", lookup_expr=‘gte‘)
pricemax = django_filters.NumberFilter(name="shop_price", lookup_expr=‘lte‘)
top_category = django_filters.NumberFilter(name="category", method=‘top_category_filter‘)

def top_category_filter(self, queryset, name, value):
# 不管當前點擊的是一級分類二級分類還是三級分類,都能找到。
return queryset.filter(Q(category_id=value) | Q(category__parent_category_id=value) | Q(
category__parent_category__parent_category_id=value))

class Meta:
model = Goods
fields = [‘pricemin‘, ‘pricemax‘]

goods/filters.py

# goods/serializers.py

from rest_framework import serializers
from .models import Goods,GoodsCategory


class CategorySerializer3(serializers.ModelSerializer):
‘‘‘三級分類‘‘‘
class Meta:
model = GoodsCategory
fields = "__all__"


class CategorySerializer2(serializers.ModelSerializer):
‘‘‘
二級分類
‘‘‘
#在parent_category字段中定義的related_name="sub_cat"
sub_cat = CategorySerializer3(many=True)
class Meta:
model = GoodsCategory
fields = "__all__"


class CategorySerializer(serializers.ModelSerializer):
"""
商品一級類別序列化
"""
sub_cat = CategorySerializer2(many=True)
class Meta:
model = GoodsCategory
fields = "__all__"


#ModelSerializer實現商品列表頁
class GoodsSerializer(serializers.ModelSerializer):
#覆蓋外鍵字段
category = CategorySerializer()
class Meta:
model = Goods
fields = ‘__all__‘

goods/serializers.py

# googd/views.py

from rest_framework.views import APIView
from goods.serializers import GoodsSerializer,CategorySerializer
from .models import Goods,GoodsCategory
from rest_framework.response import Response
from rest_framework import mixins
from rest_framework import generics
from rest_framework.pagination import PageNumberPagination
from rest_framework import viewsets
from .filters import GoodsFilter
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters


class GoodsPagination(PageNumberPagination):
‘‘‘
商品列表自定義分頁
‘‘‘
#默認每頁顯示的個數
page_size = 12
#可以動態改變每頁顯示的個數
page_size_query_param = ‘page_size‘
#頁碼參數
page_query_param = ‘page‘
#最多能顯示多少頁
max_page_size = 100


class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
‘‘‘
商品列表,分頁,搜索,過濾,排序
‘‘‘

#這裏必須要定義一個默認的排序,否則會報錯
queryset = Goods.objects.all()
# 分頁
pagination_class = GoodsPagination
#序列化
serializer_class = GoodsSerializer
filter_backends = (DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter)

# 設置filter的類為我們自定義的類
#過濾
filter_class = GoodsFilter
#搜索
search_fields = (‘name‘, ‘goods_brief‘, ‘goods_desc‘)
#排序
ordering_fields = (‘sold_num‘, ‘shop_price‘)


class CategoryViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
‘‘‘
list:
商品分類列表數據
‘‘‘

queryset = GoodsCategory.objects.filter(category_type=1)
serializer_class = CategorySerializer

goods/views.py

Django REST framework+Vue 打造生鮮超市(五)