您的位置:首页 > Web前端 > Vue.js

vue+djangorestframework打造前后端分离项目(一)之drf的ViewSet、router和跨域

2018-11-07 09:46 1311 查看

上传的图片资源目录配置:

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介绍

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框架

djangorestframework官方文档

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

django-cors-headers github地址

 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 . 重新运行项目

 

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: