Django REST framework+Vue 打造生鮮超市(五)
六、商品類別數據展示
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 打造生鮮超市(五)