返回顶部

03 | Django REST framework+Vue 生鲜超市 ——商品类别数据展示

商品类别数据接口

(1)商品分类有两个接口:

一种是全部分类:一级二级三级

 一种是某一类的分类以及商品详细信息:

 

开始写商品分类的接口

 

序列化

给分类添加三级分类的serializer

from rest_framework import serializers
from .models import Goods,GoodsCategory

class GoodsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Goods
        fields = "__all__"

class CategorySerializer3(serializers.ModelSerializer):
    class Meta:
        model = GoodsCategory
        fields = "__all__"


class CategorySerializer2(serializers.ModelSerializer):
    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__"
goods/serializers.py

 

 

编写视图函数

from goods.serializers import CategorySerializer
from .models import Goods,GoodsCategory

class CategoryViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    '''
    list:
        商品分类列表数据
    '''

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

 

说明:

  • 注释的内容,在后面生成drf文档的时候会显示出来,所有要写清楚

 url配置

 

from goods.views import CategoryViewSet

router.register(r'categorys', CategoryViewSet, base_name="categorys")
MxShop/urls.py

 

 

 访问

http://127.0.0.1:8000/categorys/

 

 访问

http://127.0.0.1:8000/categorys/1/

  

 

 

 

vue展示商品分类数据

 接口相关代码都放在src/api/api.js里面,调试接口的时候我们首先需要新建一个自己的host,然后替换要调试的host

(1)新建local_host

 

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

  

(2)替换商品类别默认的host 

 

 

 开启前端Vue项目

cnpm run dev 

访问

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

 

 

 

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"

 goods/views.py

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("shop_price", lookup_expr='gte')
    pricemax = django_filters.NumberFilter("shop_price", lookup_expr='lte')
    top_category = django_filters.NumberFilter("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与前端要一致

 

 在 goods/views.py中的 GoodsListViewSet 类中配置排序字段

ordering_fields = ('sold_num', 'shop_price')

 

(5)搜索  

 在 goods/views.py中的 GoodsListViewSet 类中配置搜索字段

 

search_fields = ('name', 'goods_brief', 'goods_desc')

  

(6)替换为local_host

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

现在就可以从后台获取商品的数据了,主要功能

  • 分类过滤
  • 价格区间过滤
  • 显示商品数量
  • 分页
  • 搜索

 

 

完整代码

from django.conf.urls import url,include
import xadmin
from MxShop.settings import MEDIA_ROOT
from django.views.static import serve
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)
router.register(r'categorys', CategoryViewSet, base_name="categorys")

urlpatterns = [
    url(r'^admin/', xadmin.site.urls),
    url(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT}),
    url(r'docs/', include_docs_urls(title="慕学生鲜")),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url('^', include(router.urls)),
]
MxShop/urls.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("shop_price", lookup_expr='gte')
    pricemax = django_filters.NumberFilter("shop_price", lookup_expr='lte')
    top_category = django_filters.NumberFilter("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
from rest_framework import serializers
from .models import Goods,GoodsCategory

class GoodsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Goods
        fields = "__all__"

class CategorySerializer3(serializers.ModelSerializer):
    class Meta:
        model = GoodsCategory
        fields = "__all__"


class CategorySerializer2(serializers.ModelSerializer):
    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__"
goods/serializers.py
from goods.serializers import GoodsSerializer
from .models import Goods
from rest_framework.response import Response
from rest_framework import mixins,viewsets
from rest_framework import generics

from rest_framework.pagination import PageNumberPagination
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().order_by('id')
    # 分页
    pagination_class = GoodsPagination
    serializer_class = GoodsSerializer
    # filter_backends = (DjangoFilterBackend,filters.SearchFilter)
    filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)

    # 设置filter的类为我们自定义的类
    filter_class = GoodsFilter
    #搜索,=name表示精确搜索,也可以使用各种正则表达式
    search_fields = ('name', 'goods_brief', 'goods_desc')
    # 排序
    ordering_fields = ('sold_num', 'shop_price')


from goods.serializers import CategorySerializer
from .models import Goods,GoodsCategory

class CategoryViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    '''
    list:
        商品分类列表数据
    '''

    queryset = GoodsCategory.objects.filter(category_type=1)
    serializer_class = CategorySerializer
goods/views.py

 

说明:

  这里有两个接口 catogry 和goods,catogry中有用的数据只有各个分类的名字和各个分类的id

  goods接口 可以根据过滤器中的top_category = id,在所有的good中检索 ,满足自己父类category_id = id(goods的父类,通过点击导航或商品分类,可能为二级也可能为三级 ) 或者                                categroy__parent_category_id = id (goods的父类,通过点击导航或商品分类,可能为二级也可能为三级)

  categroy__parent_category__parent_category_id = id ,

        只有可能是导航。来多虑数据

    

 

posted @ 2018-10-24 00:30  Crazymagic  阅读(696)  评论(0编辑  收藏  举报