• REST-framework快速构建API--初体验


    一、快速上手

    1、环境准备

    安装restframework,注册app

    pip install djangorestframework
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01.apps.App01Config',
        'rest_framework',
    ]
    

    2、url

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^publish/', views.PublishView.as_view()),
    ]
    

    3、models

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    
    from django.db import models
    
    # Create your models here.
    from django.db import models
    
    # Create your models here.
    
    
    class Book(models.Model):
        title=models.CharField(max_length=32)
        price=models.IntegerField()
        pub_date=models.DateField()
        publish=models.ForeignKey("Publish")
        authors=models.ManyToManyField("Author")
        def __str__(self):
            return self.title
    
    class Publish(models.Model):
        name=models.CharField(max_length=32)
        email=models.EmailField()
        def __str__(self):
            return self.name
    
    class Author(models.Model):
        name=models.CharField(max_length=32)
        age=models.IntegerField()
        def __str__(self):
            return self.name
    

    4、views

    基于CBV方式

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    
    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    from .models import Publish
    from rest_framework.views import APIView
    
    class PublishView(APIView):
        def get(self,request):
     
            #序列化方式4rest_framework
            from rest_framework.response import Response
            publish_list = Publish.objects.all()
            ps = PublishSerializers(publish_list, many=True)
            return Response(ps.data)
    
        def post(self,request):
            return  HttpResponse('POST')
    

    5、测试

     

    二、结果序列化

    API返回结果的形式,json是非常流行的。但是我们在序列化结果时,有多种方式,每种方式实现的方式不同。

    1、原生json方式

    import json
            publish_list = list(Publish.objects.all().values())
            return HttpResponse(json.dumps(publish_list))
    

     使用json方式对结果进行强转,先把结果强转成列表的方式,然后通过json的dumps方式对结果进行格式化。

    注意:

    这种方式实现最简单,也可以自定制需要返回的字段,通过在values中填写自己需要的字段即可。

     

    2、model_to_dict方法

    #序列化方式2
            # from django.forms.models import model_to_dict
            # publish_list = Publish.objects.all()
            # data = []
            # for obj in publish_list:
            #     data.append(model_to_dict(obj))
            # return HttpResponse(data)
    

      通过models自带的model_to_dict方法直接把obj对象转换成字典的形式,然后返回。缺点:需要把每个对象再次进行处理。

     

    3、django自带的serializers方法

    #序列化方式3
            # from django.core import serializers
            # publish_list = Publish.objects.all()
            # data = serializers.serialize("json", publish_list)
            # return HttpResponse(data)
    

      

    三、基于REST-framework序列化

    from rest_framework import serializers
    class PublishSerializers(serializers.Serializer):
        name=serializers.CharField(max_length=32)
        email=serializers.CharField()
    
    
    from rest_framework.views import APIView
    视图函数继承APIView方法
    #序列化方式4rest_framework from rest_framework.response import Response publish_list = Publish.objects.all() ps = PublishSerializers(publish_list, many=True) return Response(ps.data)

      

    既然有了前面三种方法,为什么这里还要用restframework的第四种方法呢?原因如下:

    a、对于表结构复杂的情况,前面三种没有涉及到,需要我们自己去通过写逻辑代码实现;

    b、对于我们需要的返回表结构中字段的结果,定制也是个问题,比如,我们的api只需要返回指定的几个字段;

    c、对于我们后面对资源的操作,比如POST动作,需要对结果进行保存,是不是我们每次都需要自己写create方法去保存结果呢?

    d、对于错误的处理;

    等等.....诸如此类的需要考虑的问题,rest-framework都帮我们写好了逻辑,只需要我们去调用即可。

     

    对于复杂表结构

    from rest_framework import serializers
    
    class BookSerializers(serializers.Serializer):
        title=serializers.CharField(max_length=32)
        price=serializers.IntegerField()
        pub_date=serializers.DateField()
        #一对多,可以通过source指定列名,默认为str或unicode方法显示的
        publish=serializers.CharField(source="publish.name")
        #对于多对多我们可以自定义get_field方法,将object添加进去
        authors=serializers.SerializerMethodField()
        def get_authors(self,obj):
            temp=[]
            for author in obj.authors.all():
                temp.append(author.name)
            return temp
    

     

    class BookViewSet(APIView):
    
        def get(self,request,*args,**kwargs):
            book_list=Book.objects.all()
            
            bs=BookSerializers(book_list,many=True)
            return Response(bs.data)
    

      注意:这里的many=True,表示对queryset进行操作,默认为对model对象进行操作。

    四、使用ModelSerializer

    class BookSerializers(serializers.ModelSerializer):
          class Meta:
              model=Book
              fields="__all__"
              depth=1
    

      
    保存数据:

    def post(self,request,*args,**kwargs):
           
            bs=BookSerializers(data=request.data,many=False)
            if bs.is_valid():
                # print(bs.validated_data)
                bs.save()
                return Response(bs.data)
            else:
                return HttpResponse(bs.errors)
    

      通过ModelSerializer方法,类似ModelForm方法,我们可以通过Meta类直接指定Model、fields,就能满足我们的需求。操作哪个表,提交哪些字段。save方法其实后端是调用的create方法,将我们提交的数据进行保存。

    注意:

    在BookSerializers里面,我们同样可以自定义返回多对多或一对多字段内容;

    class BookSerializers(serializers.ModelSerializer):
          class Meta:
              model=Book
              fields="__all__"
              depth=1
    publish=serializers.CharField(source="publish.name")
    authors=serializers.SerializerMethodField()
    def get_authors(self,obj):
            temp=[]
            for author in obj.authors.all():
                temp.append(author.name)
            return temp
    

      但是这里如果使用ModelSerializer方法,使用save方法时,ModelSerializer默认自带的create方法不支持多对多的保存,需要我们重载create方法:

    class BookSerializers(serializers.ModelSerializer):
    
          class Meta:
              model=Book
              fields="__all__"
              # exclude = ['authors',]
              # depth=1
    
          def create(self, validated_data):
            
              authors = validated_data.pop('authors')
              obj = Book.objects.create(**validated_data)
              obj.authors.add(*authors)
              return obj
    

      

    五、单条数据操作

    针对单条数据进行操作,比如books/1(GET/PUT/DELETE)

    class BookDetailViewSet(APIView):
    
        def get(self,request,pk):
            book_obj=Book.objects.filter(pk=pk).first()
            bs=BookSerializers(book_obj)
            return Response(bs.data)
    
        def put(self,request,pk):
            book_obj=c
            bs=BookSerializers(book_obj,data=request.data)
            if bs.is_valid():
                bs.save()
                return Response(bs.data)
            else:
                return HttpResponse(bs.errors)
        
        def delete(self,request,pk):
            Book.objects.filter(pk=pk).delete()
            return Response()
    

      

    注意:

    put进行更新数据时,需要把单条数据的每个字段写全,即使之前已经是完整的一条记录,否则会报错。

      

    六、超链接API

    class BookSerializers(serializers.ModelSerializer):
          publish= serializers.HyperlinkedIdentityField(
                         view_name='publish_detail',
                         lookup_field="publish_id",
                         lookup_url_kwarg="pk")
          class Meta:
              model=Book
              fields="__all__"
              #depth=1
    

      

    urls

    urlpatterns = [
        url(r'^books/$', views.BookViewSet.as_view(),name="book_list"),
        url(r'^books/(?P<pk>d+)$', views.BookDetailViewSet.as_view(),name="book_detail"),
        url(r'^publishers/$', views.PublishViewSet.as_view(),name="publish_list"),
        url(r'^publishers/(?P<pk>d+)$', views.PublishDetailViewSet.as_view(),name="publish_detail"),
    ]
    

      

    注意:

    1、反向解析,通过name进行命名,这个代表前面的URL,不管pk怎么变化都可以引用;

    2、view_name为反向解析的name,lookup_field为对应的哪个字段,这里的pk对应的是Model里面的id字段;

    3、lookup_url_kwarg是命名url里面的分组关键字;

    4、需要在views函数里面新增一个context={'request':request}

     

    class BookView(APIView):
        def get(self,request):
            book_list=Book.objects.all()
            bs=BookModelSerializers(book_list,many=True,context={'request': request})
            return Response(bs.data)
        def post(self,request):
            # post请求的数据
            bs=BookModelSerializers(data=request.data)
            if bs.is_valid():
                print(bs.validated_data)
                bs.save()# create方法
                return Response(bs.data)
            else:
                return Response(bs.errors)
    

    注意:这里有一个问题,使用超链接post数据的时候,会有一个报错:

    需要去掉超链接的配置才能POST数据,这里还没找到解决办法。

     

  • 相关阅读:
    《仔仔细细分析Ext》 第N2章 GridPanel的小难点 第一节 每条数据后面跟随几个操作按钮
    TextField输入验证
    Ext.FormPanel 及控件横排显示
    备份
    重写
    this关键字
    TestCircle程序分析
    java方法重载
    static关键字
    super关键字
  • 原文地址:https://www.cnblogs.com/skyflask/p/10392593.html
Copyright © 2020-2023  润新知