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数据,这里还没找到解决办法。

 

 

posted @ 2019-02-17 20:52  skyflask  阅读(594)  评论(0编辑  收藏  举报