使用Django 2.0构建Python Restful服务:六)使用rest-framework默认配置进行数据解析和渲染

上一章,我们通过使用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服务。

猜你也喜欢

发表评论

邮箱地址不会被公开。