zoukankan      html  css  js  c++  java
  • 二.drf之使用序列化编写视图

    总结:两功能
    序列化:
      a.拿到queryset --->idc = Idc.objects.all()
      b.将queryset给序列化成类---->serializer = IdcSerializer(idc, many=True)
      c.转json: --->content = JSONRenderer().render(serializer.data)用序列化类的data属性可以输出所有的数据是一个字典的,并转成json字符串
    反序列化:
      a.将字符串content转成流--->stream = BytesIO(content)
      b.将流转成序列化的数据字典--->data = JSONParser().parse(stream)
      c.将字典反序列化 -->serializer = IdcSerializer(data=data)
      d.验证并保存 --->serializer.is_valid() -->serializer.save()

     一.应用示例

      需求:把用户列表用带分页功能的展示出来。使用:视图函数+序列化类将Idc表列表取出来返回json数据。

    需求分析:两个视图函数
    def idc_list():
        get方法:
            返回所有记录
        post方法:
            创建一条记录
    def idc_detail(pk):
        get方法:
            返回指定(pk对应的)记录
        put方法:
            修改指定记录
        delete方法:
            删除这条记录

    1.get请求方法:

    (1)views.py:

    from django.shortcuts import render
    from django.http import HttpResponse
    from .models import Idc
    from .serializers import IdcSerializer
    from rest_framework.renderers import JSONRenderer
    def idc_list(request, *args, **kwargs):#接收request,位置,关键字参数
        if request.method == "GET":
            queryset = Idc.objects.all()
            serializer = IdcSerializer(queryset, many=True)
            content = JSONRenderer().render(serializer.data)
            return HttpResponse(content, content_type="application/json")
        elif request.method == "POST":
            pass
        return HttpResponse("")

    (2)apps/idcs/urls.py:

    from django.conf.urls import  url
    from .views import idc_list
    urlpatterns = [
        url(r"^idcs/$",idc_list)
    ]

    (3)devops/urls.py:

    from django.conf.urls import include, url
    from django.contrib import admin
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^', include("idcs.urls"))
    ]

    (python36env) [vagrant@CentOS7 devops]$ python manage.py runserver 0.0.0.8000 启动后效果如下

     2.编写POST--

    注意这里POST想要的数据不是request.POST的数据,drf提供了方案:它可以从我们的requset对象里直接拿,直接把request传给它就可以了。

    先django shell中测试下:

    命令行测试方式:
    (1)(python36env) [vagrant@CentOS7 ~]$ pip install httpie 安装http

    (2)(python36env) [vagrant@CentOS7 ~]$ http --json POST http://127.0.0.1:8000/idcs/ aaa=bbb bbb=ccc
    HTTP/1.1 200 OK
    Content-Length: 0
    Content-Type: text/html; charset=utf-8
    Date: Sat, 06 Jun 2020 03:34:25 GMT
    Server: WSGIServer/0.2 CPython/3.6.6
    X-Frame-Options: SAMEORIGIN

    此时就能接收到数据如下:

    (3)#python manage.py runserver 0.0.0.0:8000

    [06/Jun/2020 03:33:36] "POST /idcs HTTP/1.1" 500 60032
    {'aaa': 'bbb', 'bbb': 'ccc'}

    或用postman软件测试:  在我们做前后端分离的项目的时候,这个工具测试后台接口还是非常便利的,如果我们想要在呼叫Web API时一并夹带JSON数据时就用它
    
    (python36env) [vagrant@CentOS7 devops]$ python manage.py runserver 0.0.0.0:8000  执行就能收到提交的数据了
    {'name': 'a昆明机房', 'address': '昆明a', 'phone': '1234568', 'email': 'rock@51reboot.com', 'letter': 'kma'}
    [06/Jun/2020 04:28:37] "POST /idcs/ HTTP/1.1" 200 0

     views.py中:

    from django.shortcuts import render
    from django.http import HttpResponse
    from .models import Idc
    from .serializers import IdcSerializer
    from rest_framework.renderers import JSONRenderer
    from rest_framework.parsers import  JSONParser
    
    #重写JsonResponse类为自定义json--实现你传一data数据我帮你序列化:它其实就是把下面两函数中重复的代码(注释部分)封装到此
    class JSONResponse(HttpResponse):
        def __init__(self,data,**kwargs):
            #指定为json
            kwargs.setdefault('content_type', 'application/json')
            #把data数据转换成json格式字符串
            content = JSONRenderer().render(data)
            #把字符串给httpresponse--super是执行父类的init方法
            super(JSONResponse, self).__init__(content=content, **kwargs)
    
    def idc_list(request, *args, **kwargs):#接收request,位置,关键字参数
        if request.method == "GET":
            queryset = Idc.objects.all()
            serializer = IdcSerializer(queryset, many=True)
            return JSONResponse(serializer.data)
            # content = JSONRenderer().render(serializer.data)
            # return HttpResponse(content, content_type="application/json")
        elif request.method == "POST":
            #拿到json数据
            data = JSONParser().parse(request)
            #反序列化--把json数据给序列化类
            serializer = IdcSerializer(data=data)
            if serializer.is_valid():
                serializer.save()
                # content = JSONRenderer().render(serializer.data)
                # return HttpResponse(content, JSONRenderer().render(serializer.data))
                return JSONResponse(serializer.data)
        return HttpResponse("")

    此时命令行中也可直接测试并拿到数据:

    (python36env) [vagrant@CentOS7 devops]$ http http://127.0.0.1:8000/idcs/      get请求

    HTTP/1.1 200 OK

    [
    {
    "address": "昆明",
    "email": "rock@51reboot.com",
    "id": 1,
    "letter": "km",
    "name": "昆明机房",
    "phone": "1234568"
    },
    {
    "address": "大理",
    "email": "rock@51reboot.com",
    "id": 2,
    "letter": "dl",
    "name": "大理机房"

    3.编写idc_detail

     (1)views.py中:

    from django.shortcuts import render
    from django.http import HttpResponse
    from .models import Idc
    from .serializers import IdcSerializer
    from rest_framework.renderers import JSONRenderer
    from rest_framework.parsers import  JSONParser
    
    #重写JsonResponse类为自定义json--实现你传一data数据我帮你序列化:它其实就是把下面两函数中重复的代码(注释部分)封装到此
    class JSONResponse(HttpResponse):
        def __init__(self,data,**kwargs):
            #指定为json
            kwargs.setdefault('content_type', 'application/json')
            #把data数据转换成json格式字符串
            content = JSONRenderer().render(data)
            #把字符串给httpresponse--super是执行父类的init方法
            super(JSONResponse, self).__init__(content=content, **kwargs)
    
    def idc_list(request, *args, **kwargs):#接收request,位置,关键字参数
        if request.method == "GET":
            queryset = Idc.objects.all()
            serializer = IdcSerializer(queryset, many=True)
            return JSONResponse(serializer.data)
            # content = JSONRenderer().render(serializer.data)
            # return HttpResponse(content, content_type="application/json")
        elif request.method == "POST":
            #拿到json数据
            data = JSONParser().parse(request)
            #反序列化--把json数据给序列化类
            serializer = IdcSerializer(data=data)
            if serializer.is_valid():
                serializer.save()
                # content = JSONRenderer().render(serializer.data)
                # return HttpResponse(content, JSONRenderer().render(serializer.data))
                return JSONResponse(serializer.data)
        return HttpResponse("")
    
    def idc_detail(request, pk, *args, **kwargs):
        #先获取pk--主键,可能会出错
        try:
            idc = Idc.objects.get(pk=pk)
        #不存在则直接抛出404
        except Idc.DoesNotExist:
            return HttpResponse(satatus=404)
        #如果有pk且请求方法是get那就直接给序列化
        if request.method == "GET":
            serializer = IdcSerializer(idc)
            return JSONResponse(serializer.data)
        #put表示修改
        elif request.method == "PUT":
            #拿到数据解析参数
            content = JSONParser().parse(request)
            #idc是原始数据,data是修改成什么样的数据
            serializer = IdcSerializer(idc, data=content)
            if serializer.is_valid():
                serializer.save()
                return JSONResponse(serializer.data)
            return JSONResponse(serializer.errors, status=400)
        elif request.method == "DELETE":
            idc.delete()
            #返回空
            return HttpResponse(status=204)

    (2)apps/idcs/urls.py:

    from django.conf.urls import  url
    from .views import idc_list, idc_detail
    urlpatterns = [
        url(r"^idcs/$",idc_list),
        url(r"^idcs/(?P<pk>[0-9]+)/$",idc_detail)
    ]
    命令行测试中访问能拿到数据了:
    (python36env) [vagrant@CentOS7 devops]$ http http://127.0.0.1:8000/idcs/1/ get请求 HTTP/1.1 200 OK { "address": "昆明", "email": "rock@51reboot.com", "id": 1, "letter": "km", "name": "昆明机房", "phone": "1234568" }

    如postman测试修改第一条记录:

     (python36env) [vagrant@CentOS7 devops]$ http http://127.0.0.1:8000/idcs/1/   终端验证改的结果

    {
    "address": "昆明",
    "email": "rock@511111reboot.com",    ---->改了
    "id": 1,
    "letter": "km", 
    "name": "昆明机房",
    "phone": "1234568"
    }

    二.包装API,包装url,api_root

    1.包装API:
    用于基于函数视图的@api_view装饰器。
    用于基于类视图的APIView类。
    如下使用:

    from rest_framework.decorators import api_view #导入装饰器api
    from rest_framework import status #导入状态码
    from rest_framework.response import Response
    @api_view(["GET","POST"])
    def idc_list_v2(requset, *args, **kwargs):

    2.包装url:给我们的网址添加可选的格式后缀

    http://127.0.0.1:8000/idcs.json
    http://127.0.0.1:8000/idcs/2.json
    urls.py中导入如下方法即可解决:

    from rest_framework.urlpatterns import format_suffix_patterns
    urlpatterns = format_suffix_patterns(urlpatterns)

    3.视图集

    • REST框架包括一个用于处理ViewSets的抽象,它允许开发人员集中精力对API的状态和交互进行建模,并根据常规约定自动处理URL构造。
    • ViewSet类与View类几乎相同,不同之处在于它们提供诸如read或update之类的操作,而不是get或put等方法处理程序。
    • ViewSet类只绑定到一组方法处理程序,当它被实例化成一组视图的时候,通常通过使用一个Router类来处理自己定义URL conf的复杂性。

    4.使用路由器

    因为我们使用的是ViewSet类而不是View类,我们实际上不需要自己设计URL。将资源连接到视图和url的约定可以使用Router类自动处理。我们需要做的就是使用路由器注册相应的视图集,然后让它执行其余操作。

    5.视图(views)vs视图集(viewsets)之间的权衡

    • 使用视图集可以是一个非常有用的抽象。它有助于确保URL约定在你的API中保持一致,最大限度地减少编写所需的代码量,让你能够专注于API提供的交互和表示,而不是URLconf的细节。
    • 这并不意味着采用视图集总是正确的方法。在使用基于类的视图而不是基于函数的视图时,有一个类似的权衡要考虑。使用视图集不像单独构建视图那样明确。
  • 相关阅读:
    [置顶] 2013年工作中遇到的20个问题(Bug):161-180
    Spring 3.1.1使用Mvc配置全局日期转换器,处理日期转换异常
    Java中ThreadLocal模拟和解释
    平衡
    一步一步学数据结构之1--n(二叉树遍历--非递归实现)
    RobotFramework+Selenium2环境搭建与入门实例
    UVA10168
    ubantu系统Django安装教程
    The connection to adb is down, and a severe error has occured完整解决办法
    服务端分页
  • 原文地址:https://www.cnblogs.com/dbslinux/p/13053524.html
Copyright © 2011-2022 走看看