一,初识

前后端开发分离,就要借助API,API简单说就是开发人员提供编程接口被其他人调用,他们调用之后会返回数据供其使用,

那么什么是rest呢?,我们用一句话总结为: 用url唯一定位资源,用Http请求方式(GET, POST, DELETE, PUT)描述用户行为

rest接口规范:  不能包含动词

 1 #接口设计规范
 2 GET    127.0.0.1:8000/books/        # 获取所有数据
 3 GET    127.0.0.1:8000/books/{id}/   # 获取单条数据
 4 POST   127.0.0.1:8000/books/        # 添加一条数据
 5 DELETE 127.0.0.1:8000/books/{id}/   # 删除一条数据
 6 PUT    127.0.0.1:8000/books/{id}/   # 修改一条数据
 7             
 8 class BookView(View):
 9     def get(self, request):
10         pass
11                 
12     def post(self, request):
13         pass
14 
15             
16 class BookSingleView(View):
17     def get(self, request, nid):
18         pass
19                 
20     def delete(self, request, nid):
21         pass
22                 
23     def put(self, request, nid):
24         pass
25 
26 
27 #返回数据规范
28 GET    127.0.0.1:8000/books/        # 获取所有数据 [{}, {}, {}, {}, {}]
29 GET    127.0.0.1:8000/books/{id}/   # 获取单条数据 {}
30 POST   127.0.0.1:8000/books/        # 添加一条数据 {}新增的数据
31 DELETE 127.0.0.1:8000/books/{id}/   # 删除一条数据 返回空
32 PUT    127.0.0.1:8000/books/{id}/   # 修改一条数据 {}
33 
34 
35 #错误消息规范
36 { "error": "error_message" }
View Code

安装:

新建一个Django项目
安装restframework
>>> pip install django
>>> pip install djangorestframework

二,restframework的解析器组件

解析器组件的使用:

from django.http import JsonResponse

from rest_framework.views import APIView
from rest_framework.parsers import JSONParser, FormParser
# Create your views here.


class LoginView(APIView):
    parser_classes = [FormParser]

    def get(self, request):
        return render(request, 'parserver/login.html')

    def post(self, request):
        # request是被drf封装的新对象,基于django的request
        # request.data是一个property,用于对数据进行校验
        # request.data最后会找到self.parser_classes中的解析器
        # 来实现对数据进行解析
        
        print(request.data)  # {'username': 'alex', 'password': 123}

        return JsonResponse({"status_code": 200, "code": "OK"})

使用方式非常简单,分为如下两步:

  • from rest_framework.views import APIView
  • 继承APIView
  • 直接使用request.data就可以获取Json数据

 

三,restframework的序列化组件

序列化用于对用户请求数据进行验证和数据进行序列化(主要为了解决queryset序列化的问题)

序列化就是把对象转换成字符串,反序列化就是把字符串转换成对象

开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json之类的表示形式的方式。我们可以通过声明与Django forms非常相似的序列化器(serializers)来实现

(1),序列化组件GET接口:

models:

 1 from django.db import models
 2 
 3 # Create your models here.
 4 
 5 
 6 class Publish(models.Model):
 7     nid = models.AutoField(primary_key=True)
 8     name = models.CharField(max_length=32)
 9     city = models.CharField(max_length=32)
10     email = models.EmailField()
11 
12     def __str__(self):
13         return self.name
14 
15 
16 class Author(models.Model):
17     nid = models.AutoField(primary_key=True)
18     name = models.CharField(max_length=32)
19     age = models.IntegerField()
20 
21     def __str__(self):
22         return self.name
23 
24 
25 class Book(models.Model):
26     title = models.CharField(max_length=32)
27     publishDate = models.DateField()
28     price = models.DecimalField(max_digits=5, decimal_places=2)
29     publish = models.ForeignKey(to="Publish", to_field="nid", on_delete=models.CASCADE)
30     authors = models.ManyToManyField(to="Author")
31 
32     def __str__(self):
33         return self.title
View Code

urls:

1 from django.contrib import admin
2 from django.urls import path
3 
4 from app01 import views
5 
6 urlpatterns = [
7     path('admin/', admin.site.urls),
8     path('books/',views.BookView.as_view())
9 ]
View Code

views:

 1 from django.shortcuts import render,HttpResponse
 2 
 3 # Create your views here.
 4 from rest_framework.views import APIView
 5 from rest_framework.response import Response
 6 
 7 from app01.models import Book
 8 from app01.serializers import BookSerializer
 9 
10 
11 class BookView(APIView):
12     def get(self,request):
13         books_list = Book.objects.all()
14         serialized_books = BookSerializer(books_list,many=True)
15 
16         return Response(serialized_books.data)
View Code

我们已经通过序列化组件定义了一个符合标准的接口,定义好model和url后,使用序列化组件的步骤如下:

  • 导入序列化组件:from rest_framework import serializers
  • 定义序列化类,继承serializers.Serializer(建议单独创建一个专用的模块用来存放所有的序列化类):class BookSerializer(serializers.Serializer):pass
  • 定义需要返回的字段(字段类型可以与model中的类型不一致,参数也可以调整),字段名称必须与model中的一致
  • 在GET接口逻辑中,获取QuerySet
  • 开始序列化:将QuerySet作业第一个参数传给序列化类,many默认为False,如果返回的数据是一个列表嵌套字典的多个对象集合,需要改为many=True
  • 返回:将序列化对象的data属性返回即可

Response对象,它是DRF重新封装的响应对象。该对象在返回响应数据时会判断客户端类型(浏览器或POSTMAN),如果是浏览器,它会以web页面的形式返回,如果是POSTMAN这类工具,就直接返回Json类型的数据。

序列化类中的字段名也可以与model中的不一致,但是需要使用source参数来告诉组件原始的字段名,例如:

BookTitle = serializers.CharField(max_length=128, source="title")

对于多对多的字段,我们获取到的数据并不是我们想要的,我们需要通过以下方式获取

authors_list = serializers.SerializerMethodField()
def get_authors_list(self, authors_obj):
authors = list()
for author in authors_obj.authors.all():
authors.append(author.name)

return authors
#请注意,get_必须与字段名称一致,否则会报错

(2),序列化接口的POST接口

根据接口规范,我们不需要新增url,只需要在视图类中定义一个POST方法即可,序列化类不需要修改,如下:

 1 from rest_framework.views import APIView
 2 from rest_framework.response import Response
 3 
 4 # 当前app中的模块
 5 from .models import Book
 6 from .app_serializer import BookSerializer
 7 
 8 # Create your views here.
 9 
10 
11 class BookView(APIView):
12     def get(self, request):
13         origin_books = Book.objects.all()
14         serialized_books = BookSerializer(origin_books, many=True)
15 
16         return Response(serialized_books.data)
17 
18     def post(self, request):
19         verified_data = BookSerializer(data=request.data)
20 
21         if verified_data.is_valid():
22             book = verified_data.save()
23             # 可写字段通过序列化添加成功之后需要手动添加只读字段
24             authors = Author.objects.filter(nid__in=request.data['authors'])
25             book.authors.add(*authors)
26 
27             return Response(verified_data.data)
28         else:
29             return Response(verified_data.errors)
View Code

POST接口的实现方式,如下:

  • url定义:需要为post新增url,因为根据规范,url定位资源,http请求方式定义用户行为
  • 定义post方法:在视图类中定义post方法
  • 开始序列化:通过我们上面定义的序列化类,创建一个序列化对象,传入参数data=request.data(application/json)数据
  • 校验数据:通过实例对象的is_valid()方法,对请求数据的合法性进行校验
  • 保存数据:调用save()方法,将数据插入数据库
  • 插入数据到多对多关系表:如果有多对多字段,手动插入数据到多对多关系表
  • 返回:将插入的对象返回

因为多对多关系字段是我们自定义的,而且必须这样定义,返回的数据才有意义,而用户插入数据的时候,serializers.Serializer没有实现create,我们必须手动写create和update方法来修改数据

 1     def create(self, validated_data):
 2         # {'title': 'Python666', 'price': Decimal('66.00'), 'publish': '2'}
 3         validated_data['publish_id'] = validated_data.pop('publish')
 4         book = Book.objects.create(**validated_data)
 5 
 6         return book
 7 
 8     def update(self, instance, validated_data):
 9         # 更新数据会调用该方法
10         instance.title = validated_data.get('title', instance.title)
11         instance.publishDate = validated_data.get('publishDate', instance.publishDate)
12         instance.price = validated_data.get('price', instance.price)
13         instance.publish_id = validated_data.get('publish', instance.publish.nid)
14 
15         instance.save()
16 
17         return instance
View Code

以上方式比较繁琐,我们还有更简单数书写方式,如下:

 1 class BookSerializer(serializers.ModelSerializer):
 2     class Meta:
 3         model = Book
 4 
 5         fields = ('title',
 6                   'price',
 7                   'publish',
 8                   'authors',
 9                   'author_list',
10                   'publish_name',
11                   'publish_city'
12                   )
13         extra_kwargs = {
14             'publish': {'write_only': True},
15             'authors': {'write_only': True}
16         }
17 
18     publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name')
19     publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city')
20 
21     author_list = serializers.SerializerMethodField()
22 
23     def get_author_list(self, book_obj):
24         # 拿到queryset开始循环 [{}, {}, {}, {}]
25         authors = list()
26 
27         for author in book_obj.authors.all():
28             authors.append(author.name)
29 
30         return authors
View Code

 

(3),序列化组件的PUT接口

url:

re_path(r'books/(\d+)/$', views.BookFilterView.as_view()),

view:

 1 class BookFilterView(APIView):
 2 
 3     def put(self, request, nid):
 4         book_obj = Book.objects.get(pk=nid)
 5 
 6         serialized_data = BookSerializer(data=request.data, instance=book_obj)
 7 
 8         if serialized_data.is_valid():
 9             serialized_data.save()
10         else:
11             return Response(serialized_data.errors)
View Code

序列化类还是使用的之前的类

PUT接口逻辑的设计,分为如下几个步骤:

  • url设计:re_path(r’books/(\d+)/$’, views.BookFilterView.as_view())
  • 视图类:重新定义一个视图类
  • put方法:在视图类中定义一个put方法
  • 序列化:在序列化的过程中,需要传入当前修改的数据行,参数名为instance
  • 序列化类:不需要修改
  • url路径:请求时,发送的url必须与urls.py中定义的url完全匹配

(4),序列化组件的DELETE接口

url不变,在view里面增加一个delete方法,跟put方法同属于一个类

1     def delete(self,request,nid):
2         book_obj = Book.objects.filter(pk=nid).delete()
3         
4         return Response('111')
View Code

 

(5),单条数据的接口设计

url不变,在view里面添加一个单条数据的方法

1 def get(self, request, nid):
2         book_obj = Book.objects.get(pk=nid)
3 
4         serialized_data = BookSerializer(book_obj, many=False)
5 
6         return Response(serialized_data.data)
View Code