欢迎访问我的个人网站:www.comingnext.cn

前言

在上一篇文章,已经实现了访问指定URL就返回了指定的数据,这也体现了RESTful API的一个理念,每一个URL代表着一个资源。当然我们还知道RESTful API的另一个特性就是,发送不同的请求动作,会返还不同的响应,这篇文章就讲一下django-rest-framework这个工具在这方面给我们带来的便捷操作。


Request对象

平时我们在写Django的视图函数的时候,都会带上一个request参数,这样就能处理平时搭建网站时,浏览器访问网页时发出的常规的HttpRequest。但是现在我们导入了django-rest-framework,它能够对request进行拓展,并且提供更灵活的请求解析。这个特性体现在哪呢?请看下面这个例子:

  1. request.POST # 只能处理表单数据.只能处理POST请求
  2. request.data # 能处理各种数据。 可以处理'POST', 'PUT' 和 'PATCH'模式的请求

这个例子里面的注释已经说得很清楚,拓展后的request使用request.data就可以处理各种各样的请求了,而原本的request在处理时需要指定请求模式。


Response对象

和request对象一样,django-rest-framework也对其进行了很实用的拓展,在我上一篇文章的snippets/views.py中,我们导入了JsonResponse用于返回json格式的响应,在视图函数中是这样的:

  1. @csrf_exempt
  2. def snippet_list(request):
  3. """
  4. 列出所有已经存在的snippet或者创建一个新的snippet
  5. """
  6. if request.method == 'GET':
  7. snippets = Snippet.objects.all()
  8. serializer = SnippetSerializer(snippets, many=True)
  9. return JsonResponse(serializer.data, safe=False)
  10.  
  11. elif request.method == 'POST':
  12. data = JSONParser().parse(request)
  13. serializer = SnippetSerializer(data=data)
  14. if serializer.is_valid():
  15. serializer.save()
  16. return JsonResponse(serializer.data, status=201)
  17. return JsonResponse(serializer.errors, status=400)

也就是说,在return的时候就需要指明json格式,这样显得很不实用而且很单一,所以经过拓展后的Reponse对象就很方便了,它会根据客户端的请求头部信息来确定正确的内容类型以返回给客户端。只需如下代码:

  1. return Response(data)

稍后会改进上一篇文章的程序对此进一步的具体讲解。


状态码

我们知道发送http请求时会返回各种各样的状态吗,但是都是简单的数字,比如200、404等,这些纯数字标识符有时候可能不够明确或者客户端在使用的时候不清楚错误信息甚至是没注意看不到,所以django-rest-framework也对此进行了优化,状态码会是HTTP_400_BAD_REQUEST、HTTP_404_NOT_FOUND这种,极大的提高可读性。


装饰API视图

REST框架还提供了一个装饰器和一个类来包装视图函数,可以使用它们来写API视图,让程序能处理的情况更多。

  1. @api_view装饰器用在基于视图的方法上。
  2. APIView类用在基于视图的类上。

注意:本文使用的是基于视图方法,所以使用的是装饰器@api_view,APIview这个类暂时不会提及。

这两个东西提供的一些功能,让我们省去很多工作,比如说确保你在视图中收到Request对象或在你的Response对象中添加上下文,这样就能实现内容通信。

另外装饰器可以在接收到输入错误的request.data时抛出ParseError异常,或者在适当的时候返回405 Method Not Allowed状态码。


把这些都使用起来

上面说了这么多拓展和优化,接下来就把它们都使用起来,改进一下原本的snippets/views.py,程序如下:

  1. from rest_framework import status
  2. from rest_framework.decorators import api_view
  3. from rest_framework.response import Response
  4. from snippets.models import Snippet
  5. from snippets.serializers import SnippetSerializer
  6.  
  7. @api_view(['GET', 'POST'])
  8. def snippet_list(request):
  9. """
  10. 列出所有已经存在的snippet或者创建一个新的snippet
  11. """
  12. if request.method == 'GET':
  13. snippets = Snippet.objects.all()
  14. serializer = SnippetSerializer(snippets, many=True)
  15. return Response(serializer.data)
  16.  
  17. elif request.method == 'POST':
  18. serializer = SnippetSerializer(data=request.data)
  19. if serializer.is_valid():
  20. serializer.save()
  21. return Response(serializer.data, status=status.HTTP_201_CREATED)
  22. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

可以看出,经过改进的代码已经把上面所说的几个django-rest-framework带来的特性都应用起来了,我们可以看出程序代码量变少,并且能处理的情况更多了。 比如说,在原本的视图函数snippet_detail中,处理'PUT'请求的时候,需要先解析json格式的数据再进一步处理:

  1. data = JSONParser().parse(request)
  2. serializer = SnippetSerializer(snippet, data=data)

也就是说需要分成两步实现,而且这里有一个限制就是只能解析json格式的数据流。而改进后的程序只需一行代码:

  1. serializer = SnippetSerializer(data=request.data)

直接使用之前说的request.data就可以获取到提交过来的数据了,并且可以处理各种数据和各种请求动作,方便了开发。

还有在return的时候也不需要指定json格式了,由原本的

  1. return JsonResponse(serializer.data, status=201)

改成了

  1. return Response(serializer.data,status=status.HTTP_201_CREATED)

这也意味着返回给客户端的可以是json或者html等格式的内容,返回HTML格式的内容的话,会在浏览器返回经过渲染的、更美观的页面。同时可以看出状态码也改进成了django-rest-framework给我们带来的可读性更高的状态标识码,以上这些措施都很大程度的提高了对客户的友好度。

对于另一个视图函数的修改也是同样的原理,这里就不做同样的讲解了,代码如下:

  1. @api_view(['GET', 'PUT', 'DELETE'])
  2. def snippet_detail(request, pk):
  3. """
  4. Retrieve, update or delete a snippet instance.
  5. """
  6. try:
  7. snippet = Snippet.objects.get(pk=pk)
  8. except Snippet.DoesNotExist:
  9. return Response(status=status.HTTP_404_NOT_FOUND)
  10.  
  11. if request.method == 'GET':
  12. serializer = SnippetSerializer(snippet)
  13. return Response(serializer.data)
  14.  
  15. elif request.method == 'PUT':
  16. serializer = SnippetSerializer(snippet, data=request.data)
  17. if serializer.is_valid():
  18. serializer.save()
  19. return Response(serializer.data)
  20. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  21.  
  22. elif request.method == 'DELETE':
  23. snippet.delete()
  24. return Response(status=status.HTTP_204_NO_CONTENT)

以上就是对原有的常规的Django视图函数的改进。

总结一下就是处理request提交过来的数据不需要一定是json格式的数据,返回的响应也不需要一定是json数据,也可以是经过渲染的HTML页面。稍后就会示范使用。


向URL添加可选的格式后缀

既然上面已经说了返回给客户端的Response可是json或者是HTML等格式的内容,那么用户在使用的时候是如何指定返回哪种格式的内容呢,那就是在URL的最后加上后缀。比如http://127.0.0.1:8000/snippets.json,这样就是用户自己指定了返回json格式的Response,而不是我们在后台指定返回固定的格式。

只需对我们的程序稍加改进就可以了,在两个视图函数添加关键词参数format:

  1. def snippet_list(request, format=None):

以及

  1. def snippet_detail(request, pk, format=None):

再修改一下snippets/urls.py,导入format_suffix_patterns(格式后缀模式):

  1. from django.conf.urls import url
  2. from rest_framework.urlpatterns import format_suffix_patterns
  3. from snippets import views

  4. urlpatterns = [
  5.    url(r'^snippets/$', views.snippet_list),
  6.    url(r'^snippets/(?P<pk>[0-9]+)$', views.snippet_detail),
  7. ]
  8.  
  9. urlpatterns = format_suffix_patterns(urlpatterns)

改进后的使用

首先当然还是可以像上一篇文章中那样的使用:

也可以通过设置Accept头部信息来控制返回的格式:

  1. http http://127.0.0.1:8000/snippets/ Accept:application/json # Request JSON
  2. http http://127.0.0.1:8000/snippets/ Accept:text/html # Request HTML

效果如下(返回的是页面的HTML代码,只展示了一部分):

还可以直接加格式后缀:

  1. http http://127.0.0.1:8000/snippets.json # JSON suffix
  2. http http://127.0.0.1:8000/snippets.api # Browsable API suffix

当然啦,在命令行查看HTML代码就没啥意思了,我们可以直接在浏览器输入 http://127.0.0.1:8000/snippets.api 进行查看,会得到一个美观的页面:

如果我们要增添数据怎么办?我们可以控制 Content-Type 头部信息来提交POST请求:

  1. http --form POST http://127.0.0.1:8000/snippets/ code="print 123"
  2. http --json POST http://127.0.0.1:8000/snippets/ code="print 456"

它会自动在原有的数据后面添加你提交过去的数据,效果如下:

上面说了,改进后可以处理错误的提交,比如把code改成了codes,就会给出错误信息:

图中给出的错误信息是 400 Bad Request,这和我们在视图函数中定义的是一样的:

  1. return Response(serializer.data,status=status.HTTP_400_BAD_REQUEST)

在请求中如果加入了--debug可以查看到详细的请求信息和类型:

在上面介绍@api_view和APIView的时候,提到了在适当的时候返回405 Method Not Allowed状态码。这个所谓适当的时候就要回看到刚才写视图函数的时候,修饰器的代码:

  1. @api_view(['GET','POST'])

以及

  1. @api_view(['GET','PUT','DELETE'])

这两行代码就规定了在调用这两个函数,也就是访问到相关的URL时,只能使用指定的请求动作,否则就会报出405 Method Not Allowed错误。例如访问 http://127.0.0.1:8000/snippets.json 时用了PUT请求就会报这个错:

正确的更改数据应该如下:

  1. http --json PUT http://127.0.0.1:8000/snippets/1.json code="hello world"

这样就把 id=1 的数据修改了。想要删除也是一样的:

这样就可以把 id=3 的数据删除掉了。


OK,关于Django RESTful API的请求和响应部分的处理就先讲到这了。下一篇会介绍基于类的视图,多谢支持~

本文地址:http://www.cnblogs.com/zivwong/p/7427394.html
作者博客:ziv
欢迎转载,请在明显位置给出出处及链接

Django编写RESTful API(二):请求和响应的更多相关文章

  1. Django编写RESTful API(一):序列化

    欢迎访问我的个人网站:www.comingnext.cn 关于RESTful API 现在,在开发的过程中,我们经常会听到前后端分离这个技术名词,顾名思义,就是前台的开发和后台的开发分离开.这个技术方 ...

  2. Django编写RESTful API(四):认证和权限

    欢迎访问我的个人网站:www.comingnext.cn 前言: 按照前面几篇文章里那样做,使用Django编写RESTful API的基本功能已经像模像样了.我们可以通过不同的URL访问到不同的资源 ...

  3. Spring Boot 2.x 编写 RESTful API (二) 校验

    用Spring Boot编写RESTful API 学习笔记 约束规则对子类依旧有效 groups 参数 每个约束用注解都有一个 groups 参数 可接收多个 class 类型 (必须是接口) 不声 ...

  4. Django编写RESTful API(三):基于类的视图

    欢迎访问我的个人网站:www.comingnext.cn 前言 在上一篇文章中,主要讲的是请求和响应,项目里面views.py中的视图函数都是基于函数的,并且我们介绍了@api_view这个很有用的装 ...

  5. Django编写RESTful API(六):ViewSets和Routers

    欢迎访问我的个人网站:www.comingnext.cn 前言 在本系列的文章中,我在第一篇和第二篇文章中写的编写Django视图时,使用的都是基于函数的方法,并且每个视图函数之前都会加一个djang ...

  6. Django编写RESTful API(五):添加超链接提高模型间的关联性

    前言 在第四篇中,加入了用户模型,以及相关的认证和权限的功能.但是我们在使用的时候,会发现在访问http://127.0.0.1:8000/users/时看到的用户列表,不能够直接点击某个链接然后查看 ...

  7. 利用 Django REST framework 编写 RESTful API

    利用 Django REST framework 编写 RESTful API Updateat 2015/12/3: 增加 filter 最近在玩 Django,不得不说 rest_framewor ...

  8. RESTful规范与django编写restful接口

    一.什么是RESTful规范 ①REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” ②REST从资 ...

  9. python 全栈开发,Day95(RESTful API介绍,基于Django实现RESTful API,DRF 序列化)

    昨日内容回顾 1. rest framework serializer(序列化)的简单使用 QuerySet([ obj, obj, obj]) --> JSON格式数据 0. 安装和导入: p ...

随机推荐

  1. jsp实现上一页下一页翻页功能

    前段时间一直忙于期末考试和找实习,好久没写博客了. 这段时间做了个小项目,包含了翻页和富文本编辑器Ueditor的两个知识点,Ueditor玩的还不是很深,打算玩深后再写篇博客. 要实现翻页功能,只需 ...

  2. Tomcat解压版配置详解(Tomcat8示例)

    注:请在JDK安装后操作以下内容 1.  下载Tomcat解压缩安装包 http://mirror.bit.edu.cn/apache/tomcat/tomcat-8/v8.0.45/bin/apac ...

  3. Mybatis-多对多

    先说一下需求: 在页面上显示数据库中的所有图书,显示图书的同时,显示出该图书所属的类别(这里一本书可能同时属于多个类别) 测试环境:MySQL.MyEclipse 创建表: 笔者这里使用 中间表 连接 ...

  4. 使用stackOfIntegers实现降序素数

    使用stackOfIntegers实现降序素数 代码如下: package day06; public class TestSU { public static void main(String[] ...

  5. win10下python2与python3以及pip共存

    一 分别安装python2和python3 注意: 安装时记得勾选 Add Python.exe to Path 二 安装pip Python3最新版本有pip,无需安装 Python2: 下载pip ...

  6. 创建 Machine - 每天5分钟玩转 Docker 容器技术(46)

    对于 Docker Machine 来说,术语 Machine 就是运行 docker daemon 的主机.“创建 Machine” 指的就是在 host 上安装和部署 docker.先执行 doc ...

  7. iOS开发实战-基于SpriteKit的FlappyBird小游戏

    写在前面 最近一直在忙自己的维P恩的事情 公司项目也是一团乱 于是...随手找了个游戏项目改了改就上线了,就当充数了. SpriteKit简介 SpriteKit是iOS 7之后苹果推出的2D游戏框架 ...

  8. python3网络编程之socket

    文章内容: socket介绍 socket参数介绍 流程描述 socket对象内建方法 基本socket实例 通过socket实现简单ssh并实现接收大数据 socket介绍 socket又称&quo ...

  9. Java 三目运算符表达式的一些问题

    最近在处理一个需求,需求描述如下:对数据库中查询出来的数据的某一个字段做一个简单处理.处理方式是:如果该字段的值(取值范围0~4,有可能为null)等于0,那么默认处理成1. 测试代码如下: publ ...

  10. win10 vmware下Linux系统联网

    本来,这个问题网上资源很多的,但是就因为多,就变得杂了,对于许多新手,并不理解为啥,故记录下来方便以后使用.此处我采用配置VWmare虚拟网关(上学期刚刚学计算机网络,正好可以复习下).关于虚拟机下L ...