一,初识
前后端开发分离,就要借助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" }
安装:
新建一个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
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 ]
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)
我们已经通过序列化组件定义了一个符合标准的接口,定义好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)
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
以上方式比较繁琐,我们还有更简单数书写方式,如下:
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
(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)
序列化类还是使用的之前的类
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')
(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)
浙公网安备 33010602011771号