vue+djangorestframework打造前后端分离项目(一)之drf的ViewSet、router和跨域
上传的图片资源目录配置:
settings.py:
[code]MEDIA_URL = "/media/" MEDIA_ROOT = os.path.join(BASE_DIR, "media")
urls.py:
[code] # media上传的图片 urlpatterns = [ re_path(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT}) ]
导入商品种类数据
db_tools/import_category_data.py: 编写脚本导入数据
from db_tools.data.category_data import row_data:db_tools/data/category_data.py 下row_data为数组
[code]__author__ = "westbrook-ding" __date__ = "2018/10/26 0026 18:53" # 单独使用django的model import os import sys # os.path.realpath(__file__):获取当前脚本文件的绝对路径 # os.path.dirname(path):文件所在的目录 pwd = os.path.dirname(os.path.realpath(__file__)) # 添加模块搜索目录 djangoShop sys.path.append(pwd+"../") # 设置django配置目录 默认会在djangoShop下找 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoShop.settings') import django django.setup() # 引入商品种类class from goods.models import GoodsCategory # 引入商品种类数组 from db_tools.data.category_data import row_data # 保存数据到数据库中 for lev1_cat in row_data: lev1_instance = GoodsCategory() lev1_instance.code = lev1_cat['code'] lev1_instance.name = lev1_cat['name'] lev1_instance.category_type = 1 lev1_instance.save() for lev2_cat in lev1_cat["sub_categorys"]: lev2_instance = GoodsCategory() lev2_instance.code = lev2_cat['code'] lev2_instance.name = lev2_cat['name'] lev2_instance.category_type = 2 lev2_instance.parent_category = lev1_instance lev2_instance.save() for lev3_cat in lev2_cat["sub_categorys"]: lev3_instance = GoodsCategory() lev3_instance.code = lev3_cat['code'] lev3_instance.name = lev3_cat['name'] lev3_instance.category_type = 3 lev3_instance.parent_category = lev2_instance lev3_instance.save()
导入商品数据
db_tools/import_good_data.py: 编写脚本导入数据
from db_tools.data.product_data import row_data:db_tools/data/product_data.py 下row_data为数组
[code]__author__ = "westbrook-ding" __date__ = "2018/10/26 0026 18:53" # 单独使用django的model import os import sys # os.path.realpath(__file__):获取当前脚本文件的绝对路径 # os.path.dirname(path):文件所在的目录 pwd = os.path.dirname(os.path.realpath(__file__)) # 添加模块搜索目录 djangoShop sys.path.append(pwd+"../") # 设置django配置目录 默认会在djangoShop下找 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoShop.settings') import django django.setup() # 引入商品class from goods.models import Goods, GoodsCategory, GoodsImage # 引入商品数据数组 from db_tools.data.product_data import row_data # 保存商品数据 for good_cat in row_data: good = Goods() good.name = good_cat["name"] good.goods_brief = good_cat["desc"] if good_cat["desc"] is not None else "" good.goods_desc = good_cat["goods_desc"] if good_cat["goods_desc"] is not None else "" good.market_price = float(int(good_cat["market_price"].replace("¥", '').replace("元", ""))) good.shop_price = float(int(good_cat["sale_price"].replace("¥", '').replace("元", ""))) good.goods_front_image = good_cat["images"][0] category_name = good_cat["categorys"][-1] category = GoodsCategory.objects.filter(name=category_name) if category is not None: good.category = category[0] good.save() # 商品轮播图 for good_image in good_cat["images"]: good_image_instance = GoodsImage() good_image_instance.goods = good good_image_instance.image = good_image good_image_instance.save()
restful api介绍
djangorestframework(drf)框架
1.通过django的view实现商品列表页
goods/views_base.py:
[code]__author__ = "westbrook-ding" __date__ = "2018/10/27 0027 13:51" from django.views.generic import View from goods.models import Goods class GoodslistView(View): def get(self, request): """ 通过django的view实现商品列表页 """ 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 # dumps是将dict转化成str格式,loads是将str转化成dict格式。 return HttpResponse(json.dumps(json_list), content_type="application/json")
urls.py:
[code]from django.urls import path, include, re_path from goods.views_base import GoodslistView urlpatterns = [ # 商品列表 path('goods/', GoodslistView.as_view(), name="goods_list") ]
[code]以上代码可进一步优化如下: model_to_dict() model转化成字典
[code] from django.forms.models import model_to_dict for good in goods: # model_to_dict() model转化成字典 json_dict = model_to_dict(good) json_list.append(json_dict)
model_to_dict() 有些字段无法转换采用model序列化
[code] from django.core import serializers # django models序列化 json_list = serializers.serialize("json", goods) import json # dumps是将dict转化成str格式,loads是将str转化成dict格式。 json_list = json.loads(json_list) from django.http import HttpResponse, JsonResponse # return HttpResponse(json.dumps(json_list), content_type="application/json") return JsonResponse(json_list, safe=False)
使用djangorestframework:
1.安装drf框架
pip install djangrestframework
pip install markdown Markdown对可浏览API的支持。
pip install django-filter 过滤支持。
pip install django-crispy-forms 改进的HTML显示以进行过滤。
pip install coreapi 模式生成支持。
pip install django-guardian 对象级权限支持。
2.添加'rest_framework'
到您的INSTALLED_APPS
设置
3.如果您打算使用可浏览的API,您可能还需要添加REST框架的登录和注销视图。将以下内容添加到根
urls.py文件中
[code]re_path(r'^api-auth/', include('rest_framework.urls'))
4.配置自动生成api文档
urls.py:
[code]# 引入drf自动生成文档的方法 from rest_framework.documentation import include_docs_urls urlpatterns = [ path('doc/', include_docs_urls(title="生鲜电商api文档")) ]
5.drf用apiview来实现商品列表:
a. goods应用下 serializers.py:
[code]# 引入 rest_framework的serializers 序列化 from rest_framework import serializers class GoodsSerializer(serializers.Serializer): name = serializers.CharField(required=True, max_length=100) click_num = serializers.IntegerField(default=0) goods_front_image = serializers.ImageField()
b. goods应用下 views.py:
[code]# 引入自定义的序列化方法 from .serializers import GoodsSerializer # APIView继承的是django的View from rest_framework.views import APIView from rest_framework.response import Response from goods.models import Goods # Create your views here. class GoodslistView(APIView): """ 商品列表 """ def get(self, requset, format=None): goods = Goods.objects.all()[:10] # many = True 序列化成数组对象 goods_json = GoodsSerializer(goods, many=True) return Response(goods_json.data)
c. urls.py:
[code]from django.urls import path, include, re_path from goods.views import GoodslistView # 引入drf自动生成文档的方法 from rest_framework.documentation import include_docs_urls urlpatterns = [ # 商品列表 path('goods/', GoodslistView.as_view(), name="goods_list"), path('doc/', include_docs_urls(title="生鲜api文档")), re_path(r'^api-auth/', include('rest_framework.urls')) ]
通过 http://127.0.0.1:8000/goods 访问goods api 得到如下数据: drf 的序列化帮我们图片目录添加的/media 前缀(django没有做这一步)
6.drf的modelserializer实现商品列表功能:
goods下serializers.py:
[code]# 引入 rest_framework的serializers 序列化 from rest_framework import serializers from goods.models import Goods, GoodsCategory # ModelSerializer class GoodsCategorySerializer(serializers.ModelSerializer): class Meta: model = GoodsCategory # __all__ 序列化所有字段 fields = "__all__" class GoodsSerializer(serializers.ModelSerializer): # 将外键的id也序列化出来 覆盖category字段 category = GoodsCategorySerializer() class Meta: model = Goods # __all__ 序列化所有字段 ["name","click_num"]:筛选字段 外键会默认序列成id fields = "__all__"
views.py、urls.py写法同5.drf用apiview来实现商品列表
7.GenericView方式实现商品列表页和分页
goods应用下的views.py:
[code]# 引入自定义的序列化方法 from .serializers import GoodsSerializer # 引入drf的generics和PageNumberPagination from rest_framework import generics from rest_framework.pagination import PageNumberPagination from goods.models import Goods # 自定义商品列表分页 class GoodsPagination(PageNumberPagination): page_size = 10 # 每页10条 page_size_query_param = 'page_size' page_query_param = 'p' # 指定页码参数为p 默认为page max_page_size = 100 # 查看源码 generics.ListAPIView 继承了 mixins.ListModelMixin,和GenericAPIView,而GenericAPIView继承了views.APIView class GoodslistView(generics.ListAPIView): """ 商品列表页 """ queryset = Goods.objects.all() # 查询商品列表 serializer_class = GoodsSerializer # 序列化的类 pagination_class = GoodsPagination # 配置分页
goods下serializers.py和 urls.py写法同 6.drf的modelserializer实现商品列表功能:
8.viewsets和router实现商品列表页
goods下的views.py:
[code]# 引入自定义的序列化方法 from .serializers import GoodsSerializer # 引入drf mixins、viewsets 、PageNumberPagination from rest_framework.pagination import PageNumberPagination from rest_framework import mixins from rest_framework import viewsets from goods.models import Goods # 自定义商品列表分页 class GoodsPagination(PageNumberPagination): page_size = 10 # 每页10条 page_size_query_param = 'page_size' page_query_param = 'p' # 指定页码参数为p 默认为page max_page_size = 100 # viewsets.GenericViewSet 继承了ViewSetMixin, generics.GenericAPIView # ViewSetMixin 重写了as_view方法 使其可以使用router class GoodslistViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): """ 商品列表页 """ queryset = Goods.objects.all() # 查询商品列表页 serializer_class = GoodsSerializer # 序列化类 pagination_class = GoodsPagination # 配置分页
urls.py:
[code]from django.urls import path, include, re_path # 引入drf自动生成文档的方法 from rest_framework.documentation import include_docs_urls # 引入drf路由 from rest_framework.routers import DefaultRouter router = DefaultRouter() from goods.views import GoodslistViewSet # 商品列表router router.register(r'goods', GoodslistViewSet) urlpatterns = [ # router path('', include(router.urls)), path('doc/', include_docs_urls(title="生鲜api文档")), re_path(r'^api-auth/', include('rest_framework.urls')) ]
goods下的serializers.py同
7.GenericView方式实现商品列表页和分页
9.drf的ApiView、GenericView、ViewSet和router分析
[code]GenericViewSet(ViewSet) -drf 可使用router、动态序列化、minxin GennericApiView -drf 可使用mixin 分页等 ApiView -drf View -django minxin CreateModelMixin ListModelMixin UpdateModelMixin RetrieveModelMixin DestoryModelMixin
10. def的过滤(django_filter)
goods下的filter.py:
[code]__author__ = "westbrook-ding" import django_filters from .models import Goods # 自定义商品过滤器 class GoodsFilter(django_filters.rest_framework.FilterSet): """ 商品本店价格区间 """ # gte:>= lte:<= price__min = django_filters.NumberFilter(field_name='shop_price', lookup_expr='gte') price__max = django_filters.NumberFilter(field_name='shop_price', lookup_expr='lte') # 模糊查询 contains i:忽略大小写 不加lookup_expr="icontains" 表示全部匹配 name = django_filters.CharFilter(field_name='name', lookup_expr="icontains") class Meta: model = Goods fields = ['price__min', 'price__max', 'name']
goods下的views.py:
[code]from django_filters.rest_framework import DjangoFilterBackend from goods.filter import GoodsFilter class GoodslistViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): """ 商品列表页 """ queryset = Goods.objects.all() serializer_class = GoodsSerializer # 序列化类 pagination_class = GoodsPagination # 配置分页 # 过滤 filter_backends = (DjangoFilterBackend,) # filter_fields = ('name', 'shop_price') # 必需全部匹配 filter_class = GoodsFilter
11.drf的搜索和排序
SearchFilter搜索 OrderingFilter排序
goods下的views.py:
[code]# 引入drf filters from rest_framework import filters from goods.models import Goods class GoodslistViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): """ 商品列表页 """ queryset = Goods.objects.all() serializer_class = GoodsSerializer # 序列化类 pagination_class = GoodsPagination # 配置分页 # 搜索: filters.SearchFilter和search_field # 排序: filters.OrderingFilter 和ordering_fields filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) # 搜索 # search_fields 满足元组中所选字段的任意条件均会被筛选出来 # '^'开始 - 搜索。 # '='完全匹配。 # '@'全文搜索。(目前只支持Django的MySQL后端。) # '$'正则表达式搜索。 search_fields = ('^name', 'goods_brief', 'goods_desc') # 按字段排序 ordering_fields = ('sold_num', 'add_time')
12.商品分类数据接口(列表和详情)
goods下serializers.py:(多级分类序列化)
[code]# 引入 rest_framework的serializers 序列化 from rest_framework import serializers from goods.models import GoodsCategory # ModelSerializer # 三级大类序列化 class GoodsCategorySerializer3(serializers.ModelSerializer): class Meta: model = GoodsCategory # __all__ 序列化所有字段 fields = "__all__" # 二级大类序列化 class GoodsCategorySerializer2(serializers.ModelSerializer): # many = True: 子类有多个 sub_cat = GoodsCategorySerializer3(many=True) class Meta: model = GoodsCategory # __all__ 序列化所有字段 fields = "__all__" # 一级商品大类序列化 class GoodsCategorySerializer(serializers.ModelSerializer): # many = True: 子类有多个 通过models.py 中class GoodsCategory 字段属性 related_name="sub_cat" 关联起来 sub_cat = GoodsCategorySerializer2(many=True) class Meta: model = GoodsCategory # __all__ 序列化所有字段 fields = "__all__"
goods下views.py: (mixins.ListModelMixin:列表,mixins.RetrieveModelMixin:单个商品分类详情,通过id查询)
[code]from rest_framework import mixins from rest_framework import viewsets from goods.models import GoodsCategory # 引入自定义的序列化方法 from .serializers import GoodsCategorySerializer class CategoryListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): """ 商品分类列表 、单个分类详情(mixins.RetrieveModelMixin:请求示例id=1: http://127.0.0.1:8000/category/1/) """ # 获取一级大类 queryset = GoodsCategory.objects.filter(category_type=1) serializer_class = GoodsCategorySerializer
urls.py:
[code]# 商品分类列表router router.register(r'category', CategoryListViewSet)
13.django解决跨域问题: django-cors-headers
a.安装 pip install django-cors-headers
b. settings.py 配置如下
[code]INSTALLED_APPS = ( ... 'corsheaders', ... ) # 置于 django.middleware.csrf.CsrfViewMiddleware 之前 MIDDLEWARE = [ ... 'corsheaders.middleware.CorsMiddleware', ] CORS_ORIGIN_ALLOW_ALL = True
c . 重新运行项目
阅读更多
- Vue+Django REST framework打造生鲜电商项目:学习过程之报错信息
- Vue+Django REST framework 打造生鲜电商项目
- [Django] ModelViewSet from rest_framework and Router
- 【备忘】[全栈开发 ]Vue+Django REST framework 打造生鲜电商项目视频教程
- Vue+Django REST framework 生鲜电商项目
- Django+Vue.js搭建前后端分离项目的示例
- Django REST framework+Vue 打造生鲜超市(二)
- Django REST framework+Vue 打造生鲜超市(六)
- Django REST framework+Vue 打造生鲜超市(五)
- Django REST framework+Vue 打造生鲜超市(六)
- 使用Django + Vue.js快速而优雅地构建前后端分离项目
- Node学习(4)vue+node 前后端分离项目ajax跨域session问题解决
- Django REST framework+Vue 打造生鲜超市(三)
- Django REST framework+Vue 打造生鲜超市(七)
- Django REST framework+Vue 打造生鲜超市(八)
- Django REST framework+Vue 打造生鲜超市(一)
- Django REST framework+Vue 打造生鲜超市(八)
- vue踩坑系列——前后端分离的接口跨域问题
- 前后端分离之vue2.0+webpack2 实战项目 -- webpack介绍
- 从壹开始前后端分离【 .NET Core2.0 Api + Vue 2.0 + AOP + 分布式】框架之七 || API项目整体搭建 6.2 轻量级ORM