Django REST framework 初体验

方式一 通过django的view实现商品列表

创建一个项目drf_demo ,省略模型部分
在这里插入图片描述
apps: 存放所有app文件
media:存放所有媒体文件

settings.py文件

# 注册app
INSTALLED_APPS = [
    ......
    'users',
    'goods',
    'trade',
    'user_operation',
]

# 修改用户模型为我们的model
AUTH_USER_MODEL = 'users.UserProfile'

# 设置媒体文件存放路径
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

views_base.py

from django.views.generic.base import View,HttpResponse
from .models import Goods

class GoodsListView(View):
    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

            json_list.append(json_dict)
        from django.http import HttpResponse
        import json
        return HttpResponse(json.dumps(json_list),content_type="application/json")

url.py

from django.views.static import serve
from goods.views import GoodsListView
from .settings import MEDIA_ROOT

urlpatterns = [
    re_path(r'^media/(?P<path>.*)$',serve,{"document_root":MEDIA_ROOT}),  # 显示静态文件(图片、)
    path('goods/', GoodsListView.as_view()),
]

问题
无法序列化 DateTimeField

json_dict["add_time"]=good.add_time

在这里插入图片描述
返回json数据时,我们把每个字段都从goods中取出来再放入json_dict中,这样不仅麻烦而且容易出错.

改造1 简化model转dict

   # 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)	

问题
在这里插入图片描述
你引入model_to_dict任然无法解决序列化的问题,因此首当其冲的是要解决序列化问题

改造2 序列化数据

1、使用django的serialize

# 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)

  from django.http import HttpResponse
  return HttpResponse(json_data,content_type="application/json")

2、使用JsonResponse返回数据

	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)

答疑:
JsonResponse它会将数据序列化,因此上方我们需要先反序列化,再使用JsonResponse

# JsonResponse的源代码
data = json.dumps(data, cls=encoder, **json_dumps_params)

3、启动项目 http://127.0.0.1:8000/goods/
在这里插入图片描述
看到这里小伙伴会问,既然django内置的serialize已经可以实现上图效果,为什么还要学习DRF(Django REST framework),加大学习成本。
其一 :因为我们的图片放在media目录下,但是json数据返回的却是相对路径,我们返回给其他客户端就需要手动加域名、包名等
其二:不够灵活

方式二 Django REST framework

DRF的官网:https://www.django-rest-framework.org/tutorial/1-serialization/

DRF的前戏

安装依赖包

安装包:
	coreapi(1.32.0+-模式生成支持。
	Markdown(3.0.0+-对可浏览API的Markdown支持。
	Pygments(2.4.0+-在Markdown处理中添加语法突出显示。
	django-filter1.0.1+-过滤支持。
	django-guardian(1.1.1+-对象级别权限支持。

使用pip install 包名1 包名2 包名3 ......

修改settings.py文件

INSTALLED_APPS = [
    ...
    'rest_framework',
]

Serializer

在goods下面创建serializers.py文件

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()

修改views.py文件

from django.shortcuts import render
from .models import Goods
from .serializers import GoodsSerializer
from rest_framework.views import APIView
from rest_framework.response import Response

class GoodsListView(APIView):
    """
    List all goods
    ""
    def get(self, request, format=None):
        goods = Goods.objects.all()[:10]
        goods_serializer= GoodsSerializer(goods,many=True)
        return Response(goods_serializer.data)

修改urls.py文件

from goods.views import GoodsListView
urlpatterns = [
    ...
    path('goods/', GoodsListView.as_view()),
    url(r'^api-auth/', include('rest_framework.urls')),  # 实现登录的功能,不设置则不能登录
]

启动项目 http://127.0.0.1:8000/goods/
下图我们已经用admin登录了,不在urls.py文件中配置,则没有login选项
在这里插入图片描述

ModelSerializer

修改serializers.py文件

# serializers.py

from rest_framework import serializers
from .models import Goods
# 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"]
        fields = "__all__"   显示所有字段

启动项目 http://127.0.0.1:8000/goods/
在这里插入图片描述
让外键显示完整信息,修改serializers.py文件

# serializers.py

from rest_framework import serializers
from .models import Goods,GoodsCategory

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

class GoodsSerializer(serializers.ModelSerializer):
    category = CategorySerializer()
    class Meta:
        model = Goods
        # fields = ["name","click_num","market_price","add_time"]
        fields = "__all__"

启动项目 http://127.0.0.1:8000/goods/
在这里插入图片描述

使用mixins

修改views.py文件

from rest_framework import mixins
from rest_framework import generics

from .models import Goods
from .serializers import GoodsSerializer

class GoodsListView(mixins.ListModelMixin,
                    generics.GenericAPIView):
    """
    商品列表页
    """
    # def get(self, request, format=None):
    #     goods = Goods.objects.all()[:10]
    #     goods_serializer = GoodsSerializer(goods,many=True)
    #     return Response(goods_serializer.data)
    
    queryset = Goods.objects.all()[:10]
    serializer_class = GoodsSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

这时有的同学会问,这get就这么一句,能不能连着一句也不用写啊,当然有

使用ListAPIView

generics.py文件

# generics.py

class ListAPIView(mixins.ListModelMixin,
                  GenericAPIView):
    """
    Concrete view for listing a queryset.
    """
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

views.py文件

from rest_framework import mixins
from rest_framework import generics

from .models import Goods
from .serializers import GoodsSerializer

class GoodsListView(generics.ListAPIView):
    """
    商品列表页
    """
    queryset = Goods.objects.all()[:10]
    serializer_class = GoodsSerializer
	
	# 这里连get方法都不用写了

分页

修改views.py文件

# views.py
 """
 商品列表页
 """
 queryset = Goods.objects.all()  # 此处不要切片
 serializer_class = GoodsSerializer

修改settings.py文件

# settings.py
REST_FRAMEWORK={
    'PAGE_SIZE': 10,
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
}

修改views.py文件
注意:此时可以删除settings.py中的分页参数

# views.py
from rest_framework import generics
from rest_framework.pagination import  PageNumberPagination

from .models import Goods
from .serializers import GoodsSerializer

class GoodsResultsSetPagination(PageNumberPagination):
    page_size = 10						# 每页显示10条数据 
    page_size_query_param = 'page_size' # 页大小的参数名称
    page_query_param = 'p'				# 当前页的参数名称
    max_page_size = 1000				# 最大页大小

class GoodsListView(generics.ListAPIView):
    """
    商品列表页
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsResultsSetPagination

Viewsets

修改views.py文件

# views.py
class GoodsListViewSet(mixins.ListModelMixin,
					  viewsets.GenericViewSet):
    """
    商品列表页
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsResultsSetPagination

修改urls.py文件

# urls.py
from goods.views import GoodsListViewSet
goods_list = GoodsListViewSet.as_view({
    'get': 'list',
})

urlpatterns = [
    . . . . . .
    path('goods/', goods_list),
]

Routers

修改views.py文件

# views.py
from rest_framework.routers import DefaultRouter

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

# goods_list = GoodsListViewSet.as_view({
#     'get': 'list',
# })

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'^media/(?P<path>.*)$',serve,{"document_root":MEDIA_ROOT}),
    re_path(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path('', include(router.urls)),
]

DRF的过滤

简单过滤

修改views.py文件

# views.py
class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
    """
    商品列表页
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsResultsSetPagination

    def get_queryset(self):
        queryset = Goods.objects.all()
        price_min=self.request.query_params.get("price_min",0)
        if price_min:
            queryset=queryset.filter(shop_price__gt=int(price_min))
        return queryset

使用DjangoFilterBackend

该django-filter库包含一个DjangoFilterBackend类,该类支持针对REST框架的高度可自定义的字段筛选。
要使用DjangoFilterBackend,请先安装django-filter。然后添加django_filters到Django的INSTALLED_APPS

pip install django-filter

现在,您应该将过滤器后端添加到您的settings.py中:

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}

修改views.py文件

# views.py

...... 省略部分代码

class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
    """
    商品列表页
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsResultsSetPagination
    filterset_fields = ['name', 'shop_price']

使用DjangoFilter

地址:https://django-filter.readthedocs.io/en/master/guide/rest_framework.html#quickstart

过滤

创建filters.py文件

# filters.py
from rest_framework import generics
import django_filters
from .models import Goods

class GoodsFilter(django_filters.rest_framework.FilterSet):
    """
    商品的过滤类
    """
    price_min = django_filters.NumberFilter(field_name="shop_price", lookup_expr='gte')
    price_max = django_filters.NumberFilter(field_name="shop_price", lookup_expr='lte')

    class Meta:
        model = Goods
        fields = ['price_min', 'price_max']

修改views.py文件

# views.py

from goods.filters import GoodsFilter
class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
    ...... 省略部分代码
    
    filterset_class = GoodsFilter
搜索

修改views.py文件

# views.py

from goods.filters import GoodsFilter
class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
    ...... 省略部分代码
    
    filter_backends = [filters.SearchFilter]
    search_fields = ['name', 'goods_brief']
排序

修改views.py文件

# views.py
class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
	......省略部分代码
	
   filter_backends = [filters.SearchFilter,filters.OrderingFilter]
   ordering_fields = ['name', 'shop_price']
发布了39 篇原创文章 · 获赞 6 · 访问量 1999

猜你喜欢

转载自blog.csdn.net/weixin_45493345/article/details/103741761