第四课 Vue+Django rest framework生鲜项目资源商品列表页

第四课 Vue+Django rest framework生鲜项目资源商品列表页

第一节 django view实现商品列表页

1.1 实现商品列表页

  1. 进阶请参考django官方文档:https://docs.djangoproject.com/zh-hans/3.1/
  2. 谷歌插件JSONView用来解析json数据: 按下F5
# 新建文件views_base.py
from django.views.generic.base import View
from goods.models import Goods


class GoodsListView(View):
    # 重载get方法 默认传递request
    def get(self, request):
        """
        通过django的view实现商品列表页
        :param request:
        :return:
        """
        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
            # 这里注意 不能对datetime类型序列化 Object of type 'datetime' is not JSON serializable
            # json_dict["add_time"] = good.add_time
            json_list.append(json_dict)

        from django.http import HttpResponse
        import json
        return HttpResponse(json.dumps(json_list), content_type="application/json")
  1. 路由配置
from django.urls import path, re_path
import xadmin
from MxShop.settings import MEDIA_ROOT
from django.views.static import serve
from goods.views_base import GoodsListView

urlpatterns = [
    path('xadmin/', xadmin.site.urls),
    # 配置媒体文件夹路由地址
    re_path('media/(?P<path>.*)', serve, {'document_root': MEDIA_ROOT}, name='media'),

    # 商品列表页
    path(r'goods/', GoodsListView.as_view(), name="goods-list")
]
  1. 访问: http://127.0.0.1:8000/goods/
  2. 这样我们就通过重载django的View方式完成了列表的返回。那为什么还要使用rest framework框架呢?
    • 第一:一个个字段填充,工作量大,易出错。
    • 第二: 序列化不能序列datetime类型的字段。
    • 当然还有很多其他问题。。。

1.2 实现商品列表页优化

  1. 针对上面第一个问题优化:一个个字段填充,工作量大,易出错。
  2. from django.forms.models import model_to_dict
  3. 这里依然解决不了,datetime和ImageFieldFile字段序列化的问题。
        from django.forms.models import model_to_dict
        for good in goods:
            json_dict = model_to_dict(good)
            json_list.append(json_dict)
  1. 同时解决上面第一个和第二个问题。
  2. 使用from django.core import serializers 去系列化
		# 2. 同时解决所有字段序列化 和 手动填充问题
        from django.core import serializers
        json_data = serializers.serialize("json", goods)

        # 这里HttpResponse需要传入 序列化后的字符串
        # from django.http import HttpResponse
        # return HttpResponse(json_data, content_type="application/json")

        # 这里JsonResponse需要传入 List对象 刚好和HttpResponse传入的相反
        from django.http import JsonResponse
        import json
        json_data = json.loads(json_data)
        return JsonResponse(json_data, safe=False)
  1. 那为什么还要使用rest framework框架呢?
    • 返回给手机端会在图片路径前加很多东西,rest framework会帮我们加好
    • 返回字段的排列顺序定死了,想修改的话需要后台修改结果。还有很多不方便地方rest framework会帮我们做好
    • rest framework会帮我们自动生成文档
    • rest framework会帮我们输入检测,比如form表单还是请求体中的数据。

第二节 django-rest-framework实现商品列表页

2.1 Serializer初体验

  1. django-rest-framework简称drf
  2. django-rest-framework官方文档:https://www.django-rest-framework.org/
  3. 根据文档先安装依赖包:
    • pip install PyYAML -i https://pypi.douban.com/simple
    • pip install uritemplate -i https://pypi.douban.com/simple
    • pip install Pygments -i https://pypi.douban.com/simple
    • pip install django-guardian -i https://pypi.douban.com/simple
  4. django-rest-framework导入, 这里和课程中不同。按照官方文档来:
from django.urls import path, re_path, include
import xadmin
import rest_framework
from MxShop.settings import MEDIA_ROOT
from django.views.static import serve
# from goods.views_base import GoodsListView
from goods.views import GoodsListView
from rest_framework.schemas import get_schema_view

urlpatterns = [
    path('xadmin/', xadmin.site.urls),
    # 登陆配置 如果不配置这个看到的api页面就没有登录按钮
    path('api-auth/', include("rest_framework.urls")),
    # 配置媒体文件夹路由地址
    re_path('media/(?P<path>.*)', serve, {'document_root': MEDIA_ROOT}, name='media'),

    # 商品列表页
    path(r'goods/', GoodsListView.as_view(), name="goods-list"),
    path('openapi', get_schema_view(title="生鲜电商"), name='openapi-schema'),
]
  1. 不能忘记 配置到 INSTALLED_APPS 中。 ‘rest_framework’
  2. 我们尝试写一个class-based-views: https://www.django-rest-framework.org/tutorial/3-class-based-views/
# views.py
from goods.serializer import GoodsSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Goods
from rest_framework import status


# APIView 集成 django中的view 而且加了很多功能
class GoodsListView(APIView):
    """
    List all snippets, or create a new snippet.
    """
    def get(self, request, format=None):
        goods = Goods.objects.all()[:10]
        # many=True 列表里面有十个 如果只是一个可以不加
        goods_json = GoodsSerializer(goods, many=True)
        return Response(goods_json.data)

    def post(self, request, format=None):
        serializer = GoodsSerializer(data=request.data)
        if serializer.is_valid():
            # 这里调用serializer中的create方法
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  1. goods应用下新建serializer.py文件, 只选两个字段进行测试。
# serializer.py
from rest_framework import serializers
from goods.models import Goods


# 功能很强大 和之前的forms.py 差不多 支持序列化json
class GoodsSerializer(serializers.Serializer):
    name = serializers.CharField(required=True, max_length=100)
    click_num = serializers.IntegerField(default=0)
    # 这个字段会根据 django设置的路径自动加上 如下图
    goods_front_image = serializers.ImageField()

    # 用来保存 将上面字段全放到validated_data中
    def create(self, validated_data):
        """
        Create and return a new `Snippet` instance, given the validated data.
        """
        # 这里可以保存前段的数据
        return Goods.objects.create(**validated_data)

在这里插入图片描述

2.2 ModelSerializer简化serializers

  1. drf中的ModelSerializer和之前的Modelform一样,可以简化字段的书写。
  2. 外键中的数据也可以直接覆盖读取。
# serializer.py
from rest_framework import serializers
from goods.models import Goods, GoodsCategory


class GoodsCategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = GoodsCategory
        fields = "__all__"


# ModelSerializer功能比Serializer更强大 和之前的ModelForm 差不多
class GoodsSerializer(serializers.ModelSerializer):
    # 3. 获取外键的所有信息 实例化GoodsCategorySerializer 覆盖原有的字段
    category = GoodsCategorySerializer()

    class Meta:
        model = Goods
        # 1. 更简单 从Model中直接映射
        # fields = ['name', 'click_num', 'market_price', 'add_time']
        # 2. 取出全部 外键序列化为id
        fields = "__all__"

2.3 mixins简化views 并分页

  1. 先导入from rest_framework import mixins 和 from rest_framework import generics
  2. 方法一:可以继承mixins.ListModelMixin, generics.GenericAPIView,重写get函数
  3. 方法二:直接继承generics.ListAPIView
# views.py
from goods.serializer import GoodsSerializer
from rest_framework import mixins
from rest_framework import generics
from rest_framework.response import Response
from .models import Goods


# 必须继承ListModelMixin和GenericAPIView, 如果要接受前端发来数据还要继承CreateModelMixin
# class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):
# ListAPIView 查看源码它帮我们继承了ListModelMixin和GenericAPIView 并重写了get方法
class GoodsListView(generics.ListAPIView):
    """
    商品列表页展示
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer

    # 重载get函数
    # def get(self, request, *args, **kwargs):
    #     return self.list(request, *args, **kwargs)
  1. 通过settings.py 配置就可以完成分页。这里查看数据有一点改变,多了俩个链接,之前的数据放到results字段下。, 这些事是generics.GenericAPIView类帮我们完成的。
# 所有关于REST_FRAMEWORK配置都写在这里面
# 如何配置可以查看REST_FRAMEWORK源码中的settings.py
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 10,
}

在这里插入图片描述

  1. 定制分页的样式。 这些可以看官方文档说明。这里如果定义了,settings.py中的分页设置会覆盖掉。
# views.py
from rest_framework.pagination import PageNumberPagination


# 自定义分页的样式
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

2.4 viewsets和router配合

  1. 后续课程很多地方都是使用这种方法。
  2. 它可以帮我们做很多事情。
# views.py
from goods.serializer import GoodsSerializer
from rest_framework import generics
from .models import Goods
from rest_framework.pagination import PageNumberPagination
from rest_framework import viewsets, mixins


# 自定义分页的样式
class GoodsPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    page_query_param = 'p'
    max_page_size = 100


class GoodsListViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    商品列表页展示
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination

    # 重载get函数
    # def get(self, request, *args, **kwargs):
    #     return self.list(request, *args, **kwargs)
  1. router配置。
from goods.views import GoodsListViewset


# 可以将get请求绑定到list方法上 router配置
goods_list = GoodsListViewset.as_view({
    'get': 'list'
})


path(r'goods/', goods_list, name="goods-list"),
  1. drf 自动router 配置
    • https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/#using-routers
from goods.views import GoodsListViewset
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
# 配置goods的url
router.register(r'goods', GoodsListViewset)

# 直接添加这个就行了
path('', include(router.urls)),

第三节 drf细节探讨

2.1 drf的Apiview、GenericView、Viewset和router的原理分析

  1. GenericviewSet (viewset) 属于 drf
    • 同时继承ViewSetMixin, 允许不需要通过函数绑定 可以通过url配置时进行绑定
    • 里面有很多action。动态serializer有很多用处。
  2. GenericAPIView 属于 drf
    • 不同过滤,分页,serializer序列化的逻辑
    • 这一层级有很多混合的View。定制组合通过函数进行绑定。
  3. APIView 属于 drf
  4. view 属于django
  5. 上面的差异几乎都是通过mixin区别的。
    • CreateModelMixin
    • ListModelMixin
    • UpdateModelMixin
    • RetrieveModelMixin
    • DestoryModelMixin

2.2 drf的过滤功能

  1. 直接调用get_queryset,加入自己逻辑过滤
class GoodsListViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    商品列表页展示
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination

    # 重载get函数
    # def get(self, request, *args, **kwargs):
    #     return self.list(request, *args, **kwargs)

    # 加自己逻辑 过滤数据
    def get_queryset(self):
        queryset = Goods.objects.all()
        # 前端穿过来的数据
        price_min = self.request.query_params.get("price_min", 0)
        if price_min:
            queryset = Goods.objects.filter(shop_price__gt=int(price_min))
        return queryset
        #return Goods.objects.filter(shop_price__gt=100)
  1. 通过django_filters过滤。:https://www.django-rest-framework.org/api-guide/filtering/
    • 先在settings.py中注册进来 ‘django_filters’,
    • 这里是准确查询,name值要相等才可以,shop_price也要相等。
from django_filters.rest_framework import DjangoFilterBackend


class GoodsListViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    商品列表页展示
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination

    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name', 'shop_price']

2.3 django-filter的范围查询和模糊查询

  1. 这里我们可以了解下django-filter的官网。https://django-filter.readthedocs.io/en/stable/
  2. 自己写一个filiters.py。我们也可以自定自己过滤方法。。。看文档
# filters.py
from django_filters import rest_framework as filters
from .models import Goods


class GoodsFilter(filters.FilterSet):
    """
    商品的过滤类
    """
    min_price = filters.NumberFilter(field_name="shop_price", lookup_expr='gte')
    max_price = filters.NumberFilter(field_name="shop_price", lookup_expr='lte')
    # 模糊查询 忽略大小写icontains
    name = filters.CharFilter(field_name="name", lookup_expr='icontains')

    class Meta:
        model = Goods
        fields = ['min_price', 'max_price', 'name']
  1. views.py修改。这里注意 filterset_class = GoodsFilter
from .filters import GoodsFilter

class GoodsListViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    商品列表页展示
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination

    filter_backends = [DjangoFilterBackend]
    filterset_class = GoodsFilter

2.4 drf 的SearchFilter搜索和OrderingFilter排序

  1. 这里注意下这个SearchFilter是drf的,上面的filiter都是django的。
  2. OrderingFilter排序,也是drf框架中的。
from rest_framework import filters


class GoodsListViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    商品列表页,分页,搜索,过滤,排序
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination

    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_class = GoodsFilter
    # 查询和排序这里可以加一些正则的语法
    search_fields = ['^name', 'goods_brief', 'goods_desc']
    ordering_fields = ['sold_num', 'add_time']
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值