django rest framework之请求与响应(详解)
前言:在上一篇文章,已经实现了访问指定URL就返回了指定的数据,这也体现了RESTfulAPI的一个理念,每一个URL代表着一个资源。当然我们还知道RESTfulAPI的另一个特性就是,发送不同的请求动作,会返还不同的响应,这篇文章就讲一下django-rest-framework这个工具在这方面给我们带来的便捷操作。
一、Request对象
平时我们在写Django的视图函数的时候,都会带上一个request参数,这样就能处理平时搭建网站时,浏览器访问网页时发出的常规的HttpRequest。但是现在我们导入了django-rest-framework,它能够对request进行拓展,并且提供更灵活的请求解析。这个特性体现在哪呢?请看下面这个例子:
request.POST#Onlyhandles formdata.Onlyworksfor' POST'method. request.data#Handles arbitrary(任意的)data.Worksfor' POST','PUT'and'PATCH'methods.
request.POST只能处理前端发起的POST请求,只能处理表单提交的数据。而request.data可以处理任意数据,而不单单是前端提交的表单数据,可用于post,put,patch请求。
二、Response对象
和request对象一样,django-rest-framework也对其进行了很实用的拓展,在我上一篇文章的snippets/views.py中,我们导入了JsonResponse用于返回json格式的响应,在视图函数中是这样的:
@csrf_exempt defsnippet_list(request): """ becausewewanttobeabletoPOSTtothisviewfromclients thatwon'thaveaCSRFtokenweneedtomarktheviewascsrf_exempt Listallcodesnippets,orcreateanewsnippet. """ ifrequest.method=="GET": snippets=Snippet.objects.all() serializer=SnippetSerializer(snippets,many=True) returnJsonResponse(serializer.data,safe=False) elifrequest.method=="POST": data=JSONParser().parse(request) serializer=SnippetSerializer(data=data) ifserializer.is_valid(): serializer.save() returnJsonResponse(serializer.data,status=201) returnJsonResponse(serializer.errors,status=400)
也就是说,在return的时候就需要指明json格式,这样显得很不实用而且很单一,所以经过拓展后的Reponse对象就很方便了,它会根据客户端的请求头部信息来确定正确的内容类型以返回给客户端。只需如下代码:
returnResponse(data)# Renderstocontenttypeasrequestedbytheclient.
三、状态码
我们知道发送http请求时会返回各种各样的状态吗,但是都是简单的数字,比如200、404等,这些纯数字标识符有时候可能不够明确或者客户端在使用的时候不清楚错误信息甚至是没注意看不到,所以django-rest-framework也对此进行了优化,状态码会是HTTP_400_BAD_REQUEST、HTTP_404_NOT_FOUND这种,极大的提高可读性
四、包装API视图
REST框架提供了两个可用于编写API视图的包装器。
•@api_view装饰器用于处理基于函数的视图
•APIView类用在基于视图的类上
这些包装提供了一些功能,让我们省去很多工作。比如说确保你在视图中收到Request对象或在你的Response对象中添加上下文,这样就能实现内容通信。
另外装饰器可以在接收到输入错误的request.data时抛出ParseError异常,或者在适当的时候返回405MethodNotAllowed状态码。
五、Pullingitalltogether(使用)
Okay,let'sgoaheadandstartusingthesenewcomponentstowriteafewviews.
Wedon'tneedourJSONResponseclassinviews.pyanymore,sogoaheadanddeletethat.Oncethat'sdonewecanstartrefactoring(重构)ourviewsslightly.
在views.py文件中我们不再需要我们的JSONResponse类,所以继续删除。一旦完成,我们可以开始细微地重构我们的视图。
fromrest_frameworkimportstatus fromrest_framework.decoratorsimportapi_view fromrest_framework.responseimportResponse fromsnippets.modelsimportSnippet fromsnippets.serializersimportSnippetSerializer @api_view(['GET','POST']) defsnippet_list(request): """ Listallcodesnippets,orcreateanewsnippet. """ ifrequest.method=='GET': snippets=Snippet.objects.all() serializer=SnippetSerializer(snippets,many=True) returnResponse(serializer.data) elifrequest.method=='POST': serializer=SnippetSerializer(data=request.data) ifserializer.is_valid(): serializer.save() returnResponse(serializer.data,status=status.HTTP_201_CREATED) returnResponse(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
可以看出,经过改进的代码已经把上面所说的几个django-rest-framework带来的特性都应用起来了,我们可以看出程序代码量变少,并且能处理的情况更多了。比如说,在原本的视图函数snippet_detail中,处理'PUT'请求的时候,需要先解析前端发来的json格式的数据再进一步处理:
data=JSONParser().parse(request) serializer=SnippetSerializer(snippet,data=data)
也就是说需要分成两步实现,而且这里有一个限制就是只能解析json格式的数据流。而改进后的程序只需一行代码:
serializer=SnippetSerializer(data=request.data)
request.datacanhandleincomingjsonrequests,butitcanalsohandleotherformats.Similarlywe'rereturningresponseobjectswithdata,butallowingRESTframeworktorendertheresponseintothecorrectcontenttypeforus.
request.data就可以获取到提交过来的数据了,并且可以处理各种数据和各种请求动作,方便了开发。还有在return的时候也不需要指定json格式了,由原本的:
returnJsonResponse(serializer.data,status=201)
改成了
returnResponse(serializer.data,status=status.HTTP_201_CREATED)
这也意味着返回给客户端的可以是json或者html等格式的内容,返回HTML格式的内容的话,会在浏览器返回经过渲染的、更美观的页面。同时可以看出状态码也改进成了django-rest-framework给我们带来的可读性更高的状态标识码,以上这些措施都很大程度的提高了对客户的友好度。
对于另一个视图函数的修改也是同样的原理,这里就不做同样的讲解了,代码如下:
@api_view(['GET','PUT','DELETE']) defsnippet_detail(request,pk): """ Retrieve,updateordeleteacodesnippet. """ try: snippet=Snippet.objects.get(pk=pk) exceptSnippet.DoesNotExist: returnResponse(status=status.HTTP_404_NOT_FOUND) ifrequest.method=='GET': serializer=SnippetSerializer(snippet) returnResponse(serializer.data) elifrequest.method=='PUT': serializer=SnippetSerializer(snippet,data=request.data) ifserializer.is_valid(): serializer.save() returnResponse(serializer.data) returnResponse(serializer.errors,status=status.HTTP_400_BAD_REQUEST) elifrequest.method=='DELETE': snippet.delete() returnResponse(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:
defsnippet_list(request,format=None):
and
defsnippet_detail(request,pk,format=None):
Nowupdatetheurls.pyfileslightly,toappendasetofformat_suffix_patterns(格式后缀模式)inadditiontotheexistingURLs.
fromdjango.conf.urlsimporturl fromrest_framework.urlpatternsimportformat_suffix_patterns fromsnippetsimportviews urlpatterns=[ url(r'^snippets/$',views.snippet_list), url(r'^snippets/(?P[0-9]+)$',views.snippet_detail), ] urlpatterns=format_suffix_patterns(urlpatterns)
七、How'sitlooking?
GoaheadandtesttheAPIfromthecommandline,aswedidintutorialpart1.Everythingisworkingprettysimilarly,althoughwe'vegotsomenicererrorhandlingifwesendinvalidrequests.
Wecangetalistofallofthesnippets,asbefore.
httphttp://127.0.0.1:8000/snippets/ HTTP/1.1200OK ... [ { "id":1, "title":"", "code":"foo=\"bar\"\n", "linenos":false, "language":"python", "style":"friendly" }, { "id":2, "title":"", "code":"print\"hello,world\"\n", "linenos":false, "language":"python", "style":"friendly" } ]
Wecancontroltheformatoftheresponsethatwegetback,eitherbyusingtheAcceptheader:
httphttp://127.0.0.1:8000/snippets/Accept:application/json#RequestJSON httphttp://127.0.0.1:8000/snippets/Accept:text/html#RequestHTML
Orbyappendingaformatsuffix:
httphttp://127.0.0.1:8000/snippets.json#JSONsuffix httphttp://127.0.0.1:8000/snippets.api#BrowsableAPIsuffix
Similarly,wecancontroltheformatoftherequestthatwesend,usingtheContent-Typeheader.
#POSTusingformdata http--formPOSThttp://127.0.0.1:8000/snippets/code="print123" { "id":3, "title":"", "code":"print123", "linenos":false, "language":"python", "style":"friendly" } #POSTusingJSON http--jsonPOSThttp://127.0.0.1:8000/snippets/code="print456" { "id":4, "title":"", "code":"print456", "linenos":false, "language":"python", "style":"friendly" }
Ifyouadda--debugswitchtothehttprequestsabove,youwillbeabletoseetherequesttypeinrequestheaders.
NowgoandopentheAPIinawebbrowser,byvisitinghttp://127.0.0.1:8000/snippets/.
Browsability
BecausetheAPIchoosesthecontenttypeoftheresponsebasedontheclientrequest,itwill,bydefault,returnanHTML-formattedrepresentationoftheresourcewhenthatresourceisrequestedbyawebbrowser.ThisallowsfortheAPItoreturnafullyweb-browsableHTMLrepresentation.
Havingaweb-browsableAPIisahugeusabilitywin,andmakesdevelopingandusingyourAPImucheasier.Italsodramaticallylowersthebarrier-to-entryforotherdeveloperswantingtoinspectandworkwithyourAPI.
SeethebrowsableapitopicformoreinformationaboutthebrowsableAPIfeatureandhowtocustomizeit.
浏览功能(中文)
由于API根据客户端请求选择响应的内容类型,因此默认情况下,当Web浏览器请求资源时,将返回HTML格式的资源表示形式。这允许API返回完全的可浏览网页的HTML表示。
拥有一个可浏览网页的API是一个巨大的可用性胜利,并且使开发和使用您的API更容易。它也大大降低了想要检查和使用您的API的其他开发人员的入门障碍。
有关可浏览的API功能以及如何对其进行定制的更多信息,请参阅可浏览的api主题。
以上这篇djangorestframework之请求与响应(详解)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。