vue+drf打造前後端分離項目(一)之drf的ViewSet、router和跨域

上傳的圖片資源目錄配置:

settings.py:

MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

urls.py:

 # 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爲數組

__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爲數組

__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:

__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: 

from django.urls import path, include, re_path
from goods.views_base import GoodslistView
urlpatterns = [
    # 商品列表
    path('goods/', GoodslistView.as_view(), name="goods_list")
]
以上代碼可進一步優化如下:
model_to_dict() model轉化成字典
 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序列化

 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文件中

re_path(r'^api-auth/', include('rest_framework.urls'))

4.配置自動生成api文檔

 urls.py:

# 引入drf自動生成文檔的方法
from rest_framework.documentation import include_docs_urls
urlpatterns = [
    path('doc/', include_docs_urls(title="生鮮電商api文檔"))
]

 5.drf用apiview來實現商品列表:

  a.  goods應用下 serializers.py:

# 引入 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:

# 引入自定義的序列化方法
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:

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:

# 引入 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:

# 引入自定義的序列化方法
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:

# 引入自定義的序列化方法
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:

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分析

GenericViewSet(ViewSet)   -drf  可使用router、動態序列化、minxin
   GennericApiView        -drf  可使用mixin 分頁等
      ApiView              -drf  
        View               -django

minxin
    CreateModelMixin
    ListModelMixin
    UpdateModelMixin
    RetrieveModelMixin
    DestoryModelMixin
    

 

10. drf的過濾(django_filter)

goods下的filter.py:

__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:

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:

# 引入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:(多級分類序列化)

# 引入 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查詢)

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:

# 商品分類列表router
router.register(r'category', CategoryListViewSet)

13.django解決跨域問題:  django-cors-headers

django-cors-headers github地址

 a.安裝 pip install django-cors-headers

 b. settings.py 配置如下

INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)
# 置於 django.middleware.csrf.CsrfViewMiddleware 之前
MIDDLEWARE = [  
    ...
    'corsheaders.middleware.CorsMiddleware',  
] 
CORS_ORIGIN_ALLOW_ALL = True

c . 重新運行項目

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章