DRF对Django请求响应做了技术升级

我摘取了rendered_content()函数的代码:

@property

def rendered_content(self):

    renderer = getattr(self, 'accepted_renderer', None)

    accepted_media_type = getattr(self, 'accepted_media_type', None)

    context = getattr(self, 'renderer_context', None)

    assert renderer, ".accepted_renderer not set on Response"

    assert accepted_media_type, ".accepted_media_type not set on Response"

    assert context is not None, ".renderer_context not set on Response"

    context['response'] = self

    media_type = renderer.media_type

    charset = renderer.charset

    content_type = self.content_type

    if content_type is None and charset is not None:

        content_type = "{}; charset={}".format(media_type, charset)

    elif content_type is None:

        content_type = media_type

    self['Content-Type'] = content_type

    ret = renderer.render(self.data, accepted_media_type, context)

    if isinstance(ret, str):

        assert charset, (

            'renderer returned unicode, and did not specify '

            'a charset value.'

        )

        return ret.encode(charset)

    if not ret:

        del self['Content-Type']

    return ret

Status codes

如果在代码中直接写数字形式的状态码如400,是不容易阅读的,于是DRF提供了标识符如HTTP_400_BAD_REQUEST来替代。我列一些常见的状态码标识符:

HTTP_200_OK = 200

HTTP_201_CREATED = 201

HTTP_204_NO_CONTENT = 204

HTTP_400_BAD_REQUEST = 400

HTTP_401_UNAUTHORIZED = 401

HTTP_403_FORBIDDEN = 403

HTTP_404_NOT_FOUND = 404

HTTP_405_METHOD_NOT_ALLOWED = 405

HTTP_500_INTERNAL_SERVER_ERROR = 500

HTTP_502_BAD_GATEWAY = 502

HTTP_503_SERVICE_UNAVAILABLE = 503

HTTP_504_GATEWAY_TIMEOUT = 504

全部的状态码标识符可以在rest_framework.status模块中看到。

@api_view和APIView

DRF对API视图做了2个封装:

@api_view用于函数视图。

APIView用于类视图。

它们提供了一些新功能,比如:

检查请求是Request对象

添加上下文到Response对象

返回请求错误如405 Method Not Allowed

当request.data格式有误时,抛出ParseError异常

改造views.py

接着就用上面这几个新实现对我们之前写的snippets/views.py进行改造:

from rest_framework import status

from rest_framework.decorators import api_view

from rest_framework.response import Response

from snippets.models import Snippet

from snippets.serializers import SnippetSerializer

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

def snippet_list(request):

    """

    List all code snippets, or create a new snippet.

    """

    if request.method == 'GET':

        snippets = Snippet.objects.all()

        serializer = SnippetSerializer(snippets, many=True)

        return Response(serializer.data)

    elif request.method == 'POST':

        serializer = SnippetSerializer(data=request.data)

        if serializer.is_valid():

            serializer.save()

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

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


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

def snippet_detail(request, pk):

    """

    Retrieve, update or delete a code snippet.

    """

    try:

        snippet = Snippet.objects.get(pk=pk)

    except Snippet.DoesNotExist:

        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':

        serializer = SnippetSerializer(snippet)

        return Response(serializer.data)

    elif request.method == 'PUT':

        serializer = SnippetSerializer(snippet, data=request.data)

        if serializer.is_valid():

            serializer.save()

            return Response(serializer.data)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':

        snippet.delete()

        return Response(status=status.HTTP_204_NO_CONTENT)

改动点有这些,添加了@api_view,如:

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

使用了状态码标识符,如:

status.HTTP_404_NOT_FOUND

使用request.data替代了 data = JSONParser().parse(request),如:

serializer = SnippetSerializer(data=request.data)

使用Response()替代了JsonResponse(),如:

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

request.data和Response()能根据请求的JSON自动处理content type。

添加后缀格式(可选)

既然DRF能自动处理content type,那么也可以给URL指定具体的后缀格式,比如http://example.com/api/items/4.json。具体添加步骤是,先给view增加1个可选参数format:

def snippet_list(request, format=None):

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

再更新snippets/urls.py,添加format_suffix_patterns:

from django.urls import path

from rest_framework.urlpatterns import format_suffix_patterns

from snippets import views

urlpatterns = [

    path('snippets/', views.snippet_list),

    path('snippets/<int:pk>', views.snippet_detail),

]

urlpatterns = format_suffix_patterns(urlpatterns)

这并不是必须的,实际上也无需这么做。

测试API

http http://127.0.0.1:8000/snippets/

HTTP/1.1 200 OK

...

[

  {

    "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"

  }

]

跟之前的结果一样。再分别用form和json试试:

# POST using form data

http --form POST http://127.0.0.1:8000/snippets/ code="print(123)"

{

  "id": 3,

  "title": "",

  "code": "print(123)",

  "linenos": false,

  "language": "python",

  "style": "friendly"

}

# POST using JSON

http --json POST http://127.0.0.1:8000/snippets/ code="print(456)"

{

    "id": 4,

    "title": "",

    "code": "print(456)",

    "linenos": false,

    "language": "python",

    "style": "friendly"

}

深圳网站建设www.sz886.com

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容