Django REST framework+Vue 打造生鲜超市(五)
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 = (
- ...
- 'corsheaders',
- ...
- )
(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分页
- 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')
现在就可以从后台获取商品的数据了,主要功能
- 分类过滤
- 价格区间过滤
- 显示商品数量
- 分页
- 搜索
所有代码:
- # 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
- # 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 settings for MxShop project.
- Generated by 'django-admin startproject' using Django 2.0.2.
- For more information on this file, see
- https://docs.djangoproject.com/en/2.0/topics/settings/
- For the full list of settings and their values, see
- https://docs.djangoproject.com/en/2.0/ref/settings/
- """
- import os, sys
- # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
- BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- sys.path.insert(0, BASE_DIR)
- sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
- sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps'))
- # Quick-start development settings - unsuitable for production
- # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
- # SECURITY WARNING: keep the secret key used in production secret!
- SECRET_KEY = '#r@h(x*x2jc5o^-y#9=9w)o7iiv7jd^zxp@1s5*nj-n*s)v#o*'
- # SECURITY WARNING: don't run with debug turned on in production!
- DEBUG = True
- ALLOWED_HOSTS = []
- #重载系统的用户,让UserProfile生效
- AUTH_USER_MODEL = 'users.UserProfile'
- # Application definition
- INSTALLED_APPS = [
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'users',
- 'goods',
- 'trade',
- 'user_operation',
- 'rest_framework',
- 'xadmin',
- 'crispy_forms',
- 'DjangoUeditor',
- 'django_filters',
- 'reversion',
- 'corsheaders',
- ]
- 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',
- ]
- CORS_ORIGIN_ALLOW_ALL = True
- ROOT_URLCONF = 'MxShop.urls'
- TEMPLATES = [
- {
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [os.path.join(BASE_DIR, 'templates')]
- ,
- 'APP_DIRS': True,
- 'OPTIONS': {
- 'context_processors': [
- 'django.template.context_processors.debug',
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
- ],
- },
- },
- ]
- WSGI_APPLICATION = 'MxShop.wsgi.application'
- # Database
- # https://docs.djangoproject.com/en/2.0/ref/settings/#databases
- #
- # DATABASES = {
- # 'default': {
- # 'ENGINE': 'django.db.backends.sqlite3',
- # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
- # }
- # }
- DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.mysql',
- 'NAME': 'mxshop', #数据库名字
- 'USER': 'root', #账号
- 'PASSWORD': '123456', #密码
- 'HOST': '127.0.0.1', #IP
- 'PORT': '3306', #端口
- #这里引擎用innodb(默认myisam)
- #因为后面第三方登录时,要求引擎为INNODB
- # 'OPTIONS':{'init_command': 'SET storage_engine=INNODB'}, #按照课程会报错,改为
- "OPTIONS":{"init_command":"SET default_storage_engine=INNODB;"}
- }
- }
- # Password validation
- # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
- AUTH_PASSWORD_VALIDATORS = [
- {
- 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
- },
- ]
- # Internationalization
- # https://docs.djangoproject.com/en/2.0/topics/i18n/
- LANGUAGE_CODE = 'zh-hans'
- TIME_ZONE = 'Asia/Shanghai'
- USE_I18N = True
- USE_L10N = True
- USE_TZ = False
- # Static files (CSS, JavaScript, Images)
- # https://docs.djangoproject.com/en/2.0/howto/static-files/
- STATIC_URL = '/static/'
- # 设置上传文件的路径
- MEDIA_URL="/media/"
- MEDIA_ROOT=os.path.join(BASE_DIR,"media")
- #
- # REST_FRAMEWORK = {
- # #分页
- # 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
- # #每页显示的个数
- # 'PAGE_SIZE': 10,
- # }
settings.py
Django REST framework+Vue 打造生鲜超市(四)
Django REST framework+Vue 打造生鲜超市(三)
Django REST framework+Vue 打造生鲜超市(二)
Django REST framework+Vue 打造生鲜超市(一)
posted on 2018-04-13 00:30 zhang_derek 阅读(…) 评论(…) 编辑 收藏