使用RestFramework框架内置组件进行Django Restful接口的数据解析和渲染

点击关注州的先生

编程应用、实战教程,不容错过

上一章,我们通过使用django-rest-framework模块提供的方法和类优化了我们的序列化器和视图函数。借助于rest-framework框架的serializers.ModelSerializer序列化器,我们快速地构建了一个完整的Movie模型序列化器MovieSerializerNew()来代替之前创建的MovieSerializer()序列化器。

6.1、使用rest-framework框架的默认数据解析

因为使用了基于serializers.ModelSerializer的序列化器,所以我们可以在视图函数中,省去对请求的数据进行JSON解析的步骤,直接由MovieSerializerNew()序列化器对请求数据进行解析。

将views.py 中的视图函数movie_list()修改为以下形式:

# 代码所在文件位置为:/moviesapi/movies/views.py
@api_view(['GET','POST'])
def movie_list(request):
    if request.method == 'GET':
        # 查询所有电影信息
        movies = Movie.objects.all()
        # 实例化一个序列化器
        movies_serializer = MovieSerializerNew(movies,many=True)
        # 返回序列化的json数据
        return JsonResponse(movies_serializer.data)

    elif request.method == 'POST':
        # 解析http请求的数据
        # movie_data = JSONParser().parse(request)
        # 实例化一个序列化器
        movies_serializer = MovieSerializerNew(data=request.data)
        # 如果序列化数据有效
        if movies_serializer.is_valid():
            movies_serializer.save()
            return JsonResponse(movies_serializer.data,status=status.HTTP_201_CREATED)
        return JsonResponse(movies_serializer.errors,status=status.HTTP_400_BAD_REQUEST)

将views.py文件中的视图函数movie_detail()修改为以下形式:

# 代码所在文件位置为:/moviesapi/movies/views.py
@api_view(['GET','PUT','DELETE'])
def movie_detail(request,pk):
    # 首先判断是否存在相关数据
    try:
        movie = Movie.objects.get(pk=pk)
    except Movie.DoesNotExist:
        return HttpResponse(status=status.HTTP_404_NOT_FOUND)
    # 获取电影详情资源
    if request.method == 'GET':
        movie_serializer = MovieSerializerNew(movie)
        return JsonResponse(movie_serializer.data)

    # 修改电影详情资源
    elif request.method == 'PUT':
        # movie_data = JSONParser().parse(request)
        # MovieSerializer()序列化器接收的参数的定义来源于其基类BaseSerializer
        movie_serializer = MovieSerializerNew(movie,data=request.data)
        if movie_serializer.is_valid():
            movie_serializer.save()
            return JsonResponse(movie_serializer.data)
        return JsonResponse(movie_serializer.errors,status=status.HTTP_400_BAD_REQUEST)

    # 删除电影详情资源
    elif request.method == 'DELETE':
        movie.delete()
        return HttpResponse(status=status.HTTP_204_NO_CONTENT)

可以发现,两个视图函数中,我们都只是将:

movie_data = JSONParser().parse(request)

注释掉,并且将MovieSerializerNew()序列化器的data参数值修改为了请求的数据:

MovieSerializerNew(data=request.data)

这样,发送给服务器的请求数据就直接由序列化器进行数据解析和相关的处理。

6.2、使用rest-framework框架的默认数据渲染

看过之前文章的同学应该知道,我们在moviesapi/movies/views.py中定义了一个继承于django的HttpResponse类并用来返回json数据的响应类JsonResponse():

# 代码所在文件位置为:/moviesapi/movies/views.py
# 继承HttpResponse类,定义一个返回json数据的响应类
class JsonResponse(HttpResponse):
    def __init__(self,data,**kwargs):
        # 重写content属性,返回rest_framework的JSON渲染器渲染的数据
        content = JSONRenderer().render(data)
        # 通过kwargs设置返回的数据类型为json
        kwargs['content_type'] = 'application/json'
        super(JsonResponse,self).__init__(content,**kwargs)

所有序列化后的数据都通过这个类作为HTTP响应主体返回给浏览器。

如同序列化器,django-rest-framework也提供了现成的设计完备的响应类供我们使用,所以接下来,我们就使用的django-rest-framework模块提供的Response响应类来替换掉我们自己定义的Json响应类。

django-rest-framework模块提供的响应类位于response子模块下,使用如下代码可以直接引入:

from rest_framework.response import Response

这个Response响应类类似于Django中django.http所提供的HttpResponse响应类,两者的区别在于:

  • Response响应类使用未经渲染的数据进行初始化返回;
  • HttpResponse响应类使用经过渲染的字符串进行初始化返回;

Response响应类继承自django.template.response下的SimpleTemplateResponse类(SimpleTemplateResponse又继承自djang.http下的HttpResponse),所以它在调用过程中也会选择合适的Django模板进行响应渲染。

6.2.1、使用Response响应类

使用rest-framework提供的Response响应类作为视图函数的响应对象,我们可以完全抛弃之前自定义创建的JsonResponse()响应类。下面,将所有视图函数的响应类改为Response(),修改之后views.py文件的所有文件如下所示:

from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from movies.models import Movie
from movies.serializers import MovieSerializer,MovieSerializerNew

# Create your views here.

# 电影列表资源
@api_view(['GET','POST'])
def movie_list(request):
    if request.method == 'GET':
        # 查询所有电影信息
        movies = Movie.objects.all()
        # 实例化一个序列化器
        movies_serializer = MovieSerializerNew(movies,many=True)
        # 返回序列化的json数据
        return Response(movies_serializer.data)

    elif request.method == 'POST':
        # 解析http请求的数据
        # movie_data = JSONParser().parse(request)
        # 实例化一个序列化器
        movies_serializer = MovieSerializerNew(data=request.data)
        # 如果序列化数据有效
        if movies_serializer.is_valid():
            movies_serializer.save()
            return Response(movies_serializer.data,status=status.HTTP_201_CREATED)
        return Response(movies_serializer.errors,status=status.HTTP_400_BAD_REQUEST)

# 电影详情资源
@api_view(['GET','PUT','DELETE'])
def movie_detail(request,pk):
    # 首先判断是否存在相关数据
    try:
        movie = Movie.objects.get(pk=pk)
    except Movie.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)
    # 获取电影详情资源
    if request.method == 'GET':
        movie_serializer = MovieSerializerNew(movie)
        return Response(movie_serializer.data)

    # 修改电影详情资源
    elif request.method == 'PUT':
        # movie_data = JSONParser().parse(request)
        # MovieSerializer()序列化器接收的参数的定义来源于其基类BaseSerializer
        movie_serializer = MovieSerializerNew(movie,data=request.data)
        if movie_serializer.is_valid():
            movie_serializer.save()
            return Response(movie_serializer.data)
        return Response(movie_serializer.errors,status=status.HTTP_400_BAD_REQUEST)

    # 删除电影详情资源
    elif request.method == 'DELETE':
        movie.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

这样,我们的视图函数里面使用的完全是rest-framework框架提供的组件。现在来测试一下修改后的效果。

6.3、使用Postman测试效果

在终端界面使用python manage.py runserver命令启动项目:

使用Postman工具来对Django服务的接口进行测试,使用OPTIONS请求方法获取电影列表所支持的HTTP方法和通信的选项:

可以发现,其返回了这个接口的名称、描述、渲染选项和解析选项:

{
    "name": "Movie List",
    "description": "",
    "renders": [
        "application/json",
        "text/html"
    ],
    "parses": [
        "application/json",
        "application/x-www-form-urlencoded",
        "multipart/form-data"
    ]
}

同时在响应头中显示了允许请求的方法等信息:

我们接着来看看电影详情的OPTIONS响应,同样显示了接口的名称、描述、渲染选项和解析选项:

和允许请求的方法等信息:

使用GET方法请求这两个接口,能得到与之前一样的效果: 电影详情接口

电影列表接口

6.4、小结

在本篇,我们介绍了使用rest-framework内置的功能组件替代之前自定义创建的类和代码函数。使用这些内置组件,我们不需要过多地进行定义和设置,就能完成实现比较完善地功能。在下面地章节中,我们将更多地接触和使用rest-framework提供的组件来丰富我们的Django Restful Web服务。

原文发布于微信公众号 - 州的先生(zmister2016)

原文发表时间:2018-06-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SpringBoot 核心技术

编码规范 - 养成良好的Java编码习惯

981
来自专栏IMWeb前端团队

nodejs中错误捕获的一些最佳实践

本文作者:IMWeb yisbug 原文出处:IMWeb社区 未经同意,禁止转载 本文内容大部分来自 https://www.joyent.com/...

1896
来自专栏恰同学骚年

《C#图解教程》读书笔记之二:存储、类型和变量

  (1)C程序是一组函数和数据类型,C++程序是一组函数和类,而C#程序是一组类型声明;

633
来自专栏恰同学骚年

【译】ASP.NET应用程序和页面生命周期

  一、此文是Code Project社区2010年4月ASP.NET板块的最佳文章,说明了此文的份量;

983
来自专栏Young Dreamer

VUE中的v-if与v-show

1.共同点 都是动态显示DOM元素 2.区别 (1)手段:v-if是动态的向DOM树内添加或者删除DOM元素;v-show是通过设置DOM元素的display样...

1827
来自专栏逍遥剑客的游戏开发

Nebula3嵌入WPF

1292
来自专栏闵开慧

junit入门实例

1 junit测试用例代码 package junitTest; import static org.junit.Assert.*; import org....

3489
来自专栏Android 研究

Retrofit解析2之使用简介

前面介绍完RESTful之后,我们先来初步认识下Retrofit的使用"姿势"。本文的主要内容如下:

843
来自专栏java一日一条

Java 编程要点之 I/O 流详解

字节流处理原始的二进制数据 I/O。输入输出的是8位字节,相关的类为 InputStream 和 OutputStream.

602
来自专栏Pythonista

python之字符编码的重要思想

        unicode----->encode-------->utf-8

892

扫码关注云+社区