Vue+Django REST framework 打造生鲜电商
3-1项目初始化
虚拟环境目录
C:\Users\Lv_Shine\Envs\VueShop\Scripts\python.exe
*设置数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "mxshop",
'USER': 'root',
'PASSWORD': "root",
'HOST': "127.0.0.1",
'PORT': '3306',
'OPTIONS': {'init_command': 'SET storage_engine=INNODB;'},
}
}
options后面第三方登录要用.
运行提示
ImproperlyConfigured: Error loading MySQLdb module: No module named 'MySQLdb'.
Did you install mysqlclient or MySQL-python?
需要安装mysqlclient
坑1 运行的时候会报错
django.db.utils.OperationalError: (1193, "Unknown system variable 'storage_engine'")
解决,名字改成default_storage_engine
I have found in the following links that indeed the variable "storage_engine" has been renamed to "default_storage_engine", which has caused some software to start getting issues with recent versions of MySql.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "mxshop",
'USER': 'root',
'PASSWORD': "root",
'HOST': "127.0.0.1",
'OPTIONS': { 'init_command': 'SET default_storage_engine=INNODB;' }
}
}
用于下载各种库的win兼容版本网址
www.lfd.uci.edu/~gohlke/pythonlibs/
- 把新建的目录加入setting,可以直接form引用
import os
import 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'))
微信截图_20171201165209.png
3-2
3-7 xadmin
微信截图_20171202125759.png微信截图_20171202130117.png
安装依赖包,xadmin复制的extra_apps下.
setting添加app.
5-1 django的view方法实现商品列表
views_base.py
class GoodsListView(View):
def get(self,request):
json_list = []
goods = Goods.objects.all()[:10]
for good in goods:
json_dict = {}
json_dict["name"] = good.name
json_dict["category"] = good.category.name
json_dict["market_price"] = good.market_price
json_list.append(json_dict)
from django.http import HttpResponse
import json
return HttpResponse(json.dumps(json_list), content_type="application/json")
- url配置
url(r'goods/$', GoodsListView.as_view(), name="goods-list"),
5-2 django的serializer序列化
- 可以用这个代替会出错,图片不能序列化.
class GoodsListView(View):
def get(self,request):
json_list = []
goods = Goods.objects.all()[:10]
# for good in goods:
# json_dict = {}
# json_dict["name"] = good.name
# json_dict["category"] = good.category.name
# json_dict["market_price"] = good.market_price
# json_list.append(json_dict)
for good in goods:
json_dict = model_to_dict(good)
json_list.append(json_dict)
from django.http import HttpResponse
import json
return HttpResponse(json.dumps(json_list), content_type="application/json")
- 序列化的方式,还是不够灵活.
json_list = []
goods = Goods.objects.all()[:10]
# for good in goods:
# json_dict = {}
# json_dict["name"] = good.name
# json_dict["category"] = good.category.name
# json_dict["market_price"] = good.market_price
# json_dict["add_time"] = good.add_time
# json_list.append(json_dict)
# from django.forms.models import model_to_dict
# for good in goods:
# json_dict = model_to_dict(good)
# json_list.append(json_dict)
import json
from django.core import serializers
json_data = serializers.serialize('json', goods)
json_data = json.loads(json_data)
from django.http import HttpResponse, JsonResponse
return JsonResponse(json_data, safe=False)
5-3 apiview方式实现商品列表页-1
微信截图_20171203110238.pngpip install django-guardian
pip install coreapi
如果MarkupSafe出现错误,就需要去虚拟环境把utf-8改成gbk.
evns/vueshop/lib/site-packages/pip/compat/__init这个文件75行.
** 配置setting.添加app.
INSTALLED_APPS = {
'rest_framework',
}
- 配置urls路径
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))![微信截图_20171204213202.png](https://img.haomeiwen.com/i1716830/74c71acdef9bc6ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
5-4自定义serializer
1.urls上节配置成功了.
2.views
from rest_framework.response import Response
from rest_framework.views import APIView
from goods.models import Goods
from goods.serializers import GoodsSerializer
class GoodsListView(APIView):
def get(self, request, format=None):
goods = Goods.objects.all()[:10]
goods_serializer = GoodsSerializer(goods, many=True)
return Response(goods_serializer.data)
- serializers
from rest_framework import serializers
__author__ = 'lv'
__date__ = '2017/12/4 21:39'
class GoodsSerializer(serializers.Serializer):
name = serializers.CharField(required=True, max_length=100)
click_num = serializers.IntegerField(default=0)
成果:
微信截图_20171204214637.png点击OPTIONS会变成:
微信截图_20171204215844.png
serializers增加一个字段,浏览器请求的json就增加一个字段.
- serializers
from rest_framework import serializers
__author__ = 'lv'
__date__ = '2017/12/4 21:39'
class GoodsSerializer(serializers.Serializer):
name = serializers.CharField(required=True, max_length=100)
click_num = serializers.IntegerField(default=0)
goods_front_image = serializers.ImageField()
成果:
微信截图_20171204220221.png
目标: 使用serializers.ModelSerializer改写serializers
from rest_framework import serializers
from goods.models import Goods
__author__ = 'lv'
__date__ = '2017/12/4 21:39'
# class GoodsSerializer(serializers.Serializer):
# name = serializers.CharField(required=True, max_length=100)
# click_num = serializers.IntegerField(default=0)
# goods_front_image = serializers.ImageField()
class GoodsSerializer(serializers.ModelSerializer):
class Meta:
model = Goods
fields = ('name', 'click_num', 'market_price', 'add_time')
成果:
微信截图_20171204223236.png目标:请求所有字段
from rest_framework import serializers
from goods.models import Goods
class GoodsSerializer(serializers.ModelSerializer):
class Meta:
model = Goods
fields = "__all__"
成果:
微信截图_20171204223736.png
目标:解析goods类中的外键category
- 在serializers中添加GoodsCategorySerializer
from rest_framework import serializers
from goods.models import Goods, GoodsCategory
__author__ = 'lv'
__date__ = '2017/12/4 21:39'
class GoodsCategorySerializer(serializers.ModelSerializer):
class Meta:
model = GoodsCategory
fields = "__all__"
class GoodsSerializer(serializers.ModelSerializer):
category = GoodsCategorySerializer()
class Meta:
model = Goods
# fields = ('name', 'click_num', 'market_price', 'add_time')
fields = "__all__"
5-6
*RUN-1重写view-GoodsListView,继承mixins.ListModelMixin,generics.GenericAPIView
from django.shortcuts import render
# Create your views here.
from rest_framework import mixins, generics
from rest_framework.response import Response
from rest_framework.views import APIView
from goods.models import Goods
from goods.serializers import GoodsSerializer
# class GoodsListView(APIView):
#
# def get(self, request, format=None):
# goods = Goods.objects.all()[:10]
# goods_serializer = GoodsSerializer(goods, many=True)
# return Response(goods_serializer.data)
class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):
queryset = Goods.objects.all()[:10]
serializer_class = GoodsSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
成果:
微信截图_20171204230357.png 微信截图_20171204230639.png
-
继续简写views.py
因为:
微信截图_20171204231143.png -
所以views.py可以写成:
from django.shortcuts import render
# Create your views here.
from rest_framework import mixins, generics
from rest_framework.response import Response
from rest_framework.views import APIView
from goods.models import Goods
from goods.serializers import GoodsSerializer
# class GoodsListView(APIView):
# 第一种
# def get(self, request, format=None):
# goods = Goods.objects.all()[:10]
# goods_serializer = GoodsSerializer(goods, many=True)
# return Response(goods_serializer.data)
# class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):
# 第二种
# queryset = Goods.objects.all()[:10]
# serializer_class = GoodsSerializer
#
# def get(self, request, *args, **kwargs):
# return self.list(request, *args, **kwargs)
class GoodsListView(generics.ListAPIView):
queryset = Goods.objects.all()[:10]
serializer_class = GoodsSerializer
RUN-2 目标:分页
-
setting配置.
教程说仅仅添加'PAGE_SIZE'会无效并不会挂机.
但是pycharm会提示
微信截图_20171204233505.png
WARNINGS:
?: (rest_framework.W001) You have specified a default PAGE_SIZE pagination rest_framework setting,without specifying also a DEFAULT_PAGINATION_CLASS.
HINT: The default for DEFAULT_PAGINATION_CLASS is None. In previous versions this was PageNumberPagination. If you wish to define PAGE_SIZE globally whilst defining pagination_class on a per-view basis you may silence this check.
System check identified 1 issue (0 silenced).
警告:
?:(rest_framework.W001)您已经指定了一个默认的PAGE_SIZE分页rest_framework设置,而没有指定一个DEFAULT_PAGINATION_CLASS。
提示:DEFAULT_PAGINATION_CLASS的默认值是None。 在以前的版本中,这是PageNumberPagination。 如果您希望全局定义PAGE_SIZE,同时在每个视图上定义pagination_class,则可以使此检查无效。
REST_FRAMEWORK = {
'PAGE_SIZE': 10
}
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 10,
}
-
成果:
微信截图_20171204233825.png
RUN-3 定制分页
微信截图_20171204234448.png- 不需要设置setting只需更改views
class GoodsPagination(PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
page_query_param = "p"
max_page_size = 100
class GoodsListView(generics.ListAPIView):
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
微信截图_20171204235344.png
5-7viewsets和router
目标是引入router
RUN-4
- 改写views.py
from django.shortcuts import render
# Create your views here.
from rest_framework import mixins, generics, viewsets
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.views import APIView
from goods.models import Goods
from goods.serializers import GoodsSerializer
class GoodsPagination(PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
page_query_param = "p"
max_page_size = 100
# class GoodsListView(APIView):
# 第一种
# def get(self, request, format=None):
# goods = Goods.objects.all()[:10]
# goods_serializer = GoodsSerializer(goods, many=True)
# return Response(goods_serializer.data)
# class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):
# 第二种
# queryset = Goods.objects.all()[:10]
# serializer_class = GoodsSerializer
#
# def get(self, request, *args, **kwargs):
# return self.list(request, *args, **kwargs)
# class GoodsListView(generics.ListAPIView):
# queryset = Goods.objects.all()
# serializer_class = GoodsSerializer
# pagination_class = GoodsPagination
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
引入router
商品列表页
"""
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
- urls
good_list = GoodsListViewSet.as_view(
{
'get': 'list',
}
)
``````
url(r'goods/$', good_list, name="goods-list"),
``````
RUN-5 router改写urls
- urls
"""MxShop URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url, include
from django.contrib import admin
from django.db import router
from django.views.static import serve
from rest_framework.documentation import include_docs_urls
from rest_framework.routers import DefaultRouter
import xadmin
from MxShop.settings import MEDIA_ROOT
from goods.views import GoodsListView, GoodsListViewSet
# good_list = GoodsListViewSet.as_view(
# {
# 'get': 'list',
#
# }
# )
router = DefaultRouter()
router.register(r'goods', GoodsListViewSet),
urlpatterns = [
url(r'^xadmin/', xadmin.site.urls),
url(r'^media/(?P<path>.*)$',serve,{"document_root": MEDIA_ROOT}),
# url(r'goods/$', good_list, name="goods-list"),
url(r'^', include(router.urls)),
url(r'docs/', include_docs_urls(title="慕雪生鲜")),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
5-8
微信截图_20171205084100.png- generic 通用
- retrieve 取回
5-10 过滤
微信截图_20171205091625.pngRUN-6 过滤
- 添加APPS到setting
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'DjangoUeditor',
'users.apps.UsersConfig',
'goods.apps.GoodsConfig',
'trade.apps.TradeConfig',
'user_operation.apps.UserOperationConfig',
'crispy_forms',
'django_filters',
'xadmin',
'rest_framework',
]
- views
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
引入router
商品列表页
"""
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend,)
filter_fields = ('name', 'shop_price')
成果:
微信截图_20171205092611.png
RUN-7 区段过滤
- filters.py
# _*_ coding: utf-8 _*_
import django_filters
from goods.models import Goods
__author__ = 'lv'
__date__ = '2017/12/5 10:17'
class GoodsFilter(django_filters.rest_framework.FilterSet):
price_min = django_filters.NumberFilter(name='shop_price', lookup_expr='gte')
price_max = django_filters.NumberFilter(name='shop_price', lookup_expr='lte')
class Meta:
model = Goods
fields = ['price_min', 'price_max']
- views
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
引入router
商品列表页
"""
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend,)
filter_class = GoodsFilter
成果:
微信截图_20171205102909.png
RUN-8 查询关键词
- view
# _*_ coding: utf-8 _*_
import django_filters
from goods.models import Goods
__author__ = 'lv'
__date__ = '2017/12/5 10:17'
class GoodsFilter(django_filters.rest_framework.FilterSet):
price_min = django_filters.NumberFilter(name='shop_price', lookup_expr='gte')
price_max = django_filters.NumberFilter(name='shop_price', lookup_expr='lte')
name = django_filters.CharFilter(name='name', lookup_expr='icontains')
class Meta:
model = Goods
fields = ['price_min', 'price_max', 'name']
微信截图_20171205103749.png
RUN-9 搜索
- 只更改views很少的代码
from rest_framework import filters
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
引入router
商品列表页
"""
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend, filters.SearchFilter)
filter_class = GoodsFilter
search_fields = ('name', 'goods_brief', 'goods_desc')
成果:
微信截图_20171205104454.png
searche 字段可以匹配正则.
RUN-10 排序
- views
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
引入router
商品列表页
"""
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
filter_class = GoodsFilter
search_fields = ('name', 'goods_brief', 'goods_desc')
ordering_fields = ('sold_num', 'add_time')
成果:
微信截图_20171205110557.png