rest_framework框架的安装与序列化
rest_framework的安装
pip install django # django的安装,rest_framework是基于django的 pip install djangorestframework # rest_framework的安装
序列化
开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json
之类的表示形式的方式。我们可以通过声明与Django forms非常相似的序列化器(serializers)来实现。
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
django原生序列化方式
views.py部分:
from django.shortcuts import render, HttpResponse # Create your views here. from django.views import View from app01 import models class BookView(View): def get(self, request): import json # 序列化方式1: book_list = list(models.Book.objects.all().values("title", "price", "pub_date")) return HttpResponse(json.dumps(book_list)) # 序列化方式2: 利用model_to_dict把对象转换成dict形式 from django.forms import model_to_dict book_list = models.Book.objects.all() temp = [] for book_obj in book_list: temp.append(model_to_dict(book_obj)) print(temp) return HttpResponse("ok") # 序列化方式3:利用django内置的serializers from django.core import serializers book_list = models.Book.objects.all() ret = serializers.serialize("json", book_list) return HttpResponse(json.dumps(ret))
rest_framework组件序列化
Serializer
views.py部分:
from django.shortcuts import render # Create your views here. from app01 import models from rest_framework.views import APIView from rest_framework import serializers from rest_framework.response import Response # 为queryset,model对象做序列化 class BookSerializers(serializers.Serializer): title = serializers.CharField(max_length=32) price = serializers.IntegerField() pub_date = serializers.DateField() publish = serializers.CharField(source="publish.name") # 一对多字段序列化 # 多对多字段序列化 authors = serializers.SerializerMethodField() #定义函数处理多对多序列化,函数命名必须为:get_多对多字段 def get_authors(self, obj): temp = [] for author in obj.authors.all(): temp.append(author.name) return temp ''' 序列化BookSerializers(book_list,many=True)过程: temp=[] for obj in book_list: temp.append({ "title":obj.title, "price":obj.price, "pub_date":obj.pub_date, "publish":obj.publish, # 相当:str(obj.publish),source="publish.name"相当于:obj.publish.name #"authors":obj.authors.all, "authors": get_authors(obj) }) ''' class BookView(APIView): def get(self, request): book_list = models.Book.objects.all() # 如:传入一个queryset时,many=True,如:obj对象时,不需要many bs = BookSerializers(book_list, many=True) return Response(bs.data)
ModelSerializer
views.py部分:
from django.shortcuts import render # Create your views here. from app01 import models from rest_framework.views import APIView from rest_framework import serializers from rest_framework.response import Response # 为queryset,model对象做序列化 class BookSerializers(serializers.ModelSerializer): # 继承serializers.ModelSerializer class Meta: model = models.Book fields = "__all__" # 对于一对多,多对多时,序列化的结果值是id值,所以需要另配置,跟serializers.Serializer一样 publish = serializers.CharField(source="publish.name") # 一对多字段序列化 # 多对多字段序列化 authors = serializers.SerializerMethodField() #定义函数处理多对多序列化,函数命名必须为:get_多对多字段 def get_authors(self, obj): temp = [] for author in obj.authors.all(): temp.append(author.name) return temp class BookView(APIView): def get(self, request): book_list = models.Book.objects.all() # 如:传入一个queryset时,many=True,如:obj对象时,不需要many bs = BookSerializers(book_list, many=True) return Response(bs.data)
提交post请求
class BookView(APIView): def post(self, request): # post请求的数据 bs = BookSerializers(data=request.data) #用户提交的数据request.data if bs.is_valid(): # 数据是否合法 bs.save() # 相当执行ModelSerializer下的create方法 return Response(bs.data) # 返回保存的数据 else: return Response(bs.errors) # 返回错误信息
如果ModelSerializer自定义了一对多,多对多字段,save()存储报错,需要重写save中的create方法
重写save中的create方法
class BookSerializers(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__" # exclude = ['authors',] # depth=1 def create(self, validated_data): # 所以合法数据存储的validated_data里 authors = validated_data.pop('authors') # 相当Book.objects.create(title=validated_data["title"],price=validated_data["price"],pub_date=validated_data["pub_date"] obj = models.Book.objects.create(**validated_data) # 打散 obj.authors.add(*authors) return obj
单条数据的get和put请求
class BookDetailViewSet(APIView): def get(self,request,pk): book_obj=models.Book.objects.filter(pk=pk).first() bs=BookSerializers(book_obj) return Response(bs.data) def put(self,request,pk): book_obj=models.Book.objects.filter(pk=pk).first() bs=BookSerializers(book_obj,data=request.data) # 添加一条内容 if bs.is_valid(): bs.save() return Response(bs.data) else: return HttpResponse(bs.errors)
urls部分:
urlpatterns = [ url(r'^books/(?P<pk>\d+)$', views.BookDetailViewSet.as_view(),name="book_detail"), ]
超链接API:Hyperlinked
一对多字段序列化数据显示超链接:
[ { "id": 1, "publish": "http://127.0.0.1:8000/publishers/1", "title": "三体", "price": 233, "pub_date": null, "authors": [ 1, 2 ] } ]
views部分:
class BookSerializers(serializers.ModelSerializer): publish= serializers.HyperlinkedIdentityField( view_name='publish_detail', # url反向解析名字 lookup_field="publish_id", # 关联id字段 lookup_url_kwarg="pk") # url分组名称 class Meta: model=models.Book fields="__all__"
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"), ]
视图三部曲
from rest_framework.views import APIView from rest_framework.response import Response from .models import * from django.shortcuts import HttpResponse from django.core import serializers from rest_framework import serializers class BookSerializers(serializers.ModelSerializer): class Meta: model=Book fields="__all__" #depth=1 class PublshSerializers(serializers.ModelSerializer): class Meta: model=Publish fields="__all__" depth=1 class BookViewSet(APIView): def get(self,request,*args,**kwargs): book_list=Book.objects.all() bs=BookSerializers(book_list,many=True,context={'request': request}) return Response(bs.data) def post(self,request,*args,**kwargs): print(request.data) 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) class BookDetailViewSet(APIView): def get(self,request,pk): book_obj=Book.objects.filter(pk=pk).first() bs=BookSerializers(book_obj,context={'request': request}) return Response(bs.data) def put(self,request,pk): book_obj=Book.objects.filter(pk=pk).first() bs=BookSerializers(book_obj,data=request.data,context={'request': request}) if bs.is_valid(): bs.save() return Response(bs.data) else: return HttpResponse(bs.errors) class PublishViewSet(APIView): def get(self,request,*args,**kwargs): publish_list=Publish.objects.all() bs=PublshSerializers(publish_list,many=True,context={'request': request}) return Response(bs.data) def post(self,request,*args,**kwargs): bs=PublshSerializers(data=request.data,many=False) if bs.is_valid(): # print(bs.validated_data) bs.save() return Response(bs.data) else: return HttpResponse(bs.errors) class PublishDetailViewSet(APIView): def get(self,request,pk): publish_obj=Publish.objects.filter(pk=pk).first() bs=PublshSerializers(publish_obj,context={'request': request}) return Response(bs.data) def put(self,request,pk): publish_obj=Publish.objects.filter(pk=pk).first() bs=PublshSerializers(publish_obj,data=request.data,context={'request': request}) if bs.is_valid(): bs.save() return Response(bs.data) else: return HttpResponse(bs.errors)
每添加一表新表,复制一套代码,这样就出现很多重复代码。
mixin类编写视图
通过继承mixin类,mixins.ListModelMixin(查看所有数据),mixins.CreateModelMixin(添加数据),mixins.RetrieveModelMixin(查看单条数据),mixins.UpdateModelMixin(更新单条数据),mixins.DestroyModelMixin(删除数据),generics.GenericAPIView(最后必须继承的类),重写视图来减少代码。
from rest_framework import mixins from rest_framework import generics class BookViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView): queryset = Book.objects.all() serializer_class = BookSerializers def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs) class BookDetailViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView): queryset = Book.objects.all() serializer_class = BookSerializers def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
使用通用的基于类的视图
通过使用mixin类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。REST框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py
模块。
from rest_framework import mixins from rest_framework import generics class BookViewSet(generics.ListCreateAPIView): queryset = Book.objects.all() serializer_class = BookSerializers class BookDetailViewSet(generics.RetrieveUpdateDestroyAPIView): queryset = Book.objects.all() serializer_class = BookSerializers class PublishViewSet(generics.ListCreateAPIView): queryset = Publish.objects.all() serializer_class = PublshSerializers class PublishDetailViewSet(generics.RetrieveUpdateDestroyAPIView): queryset = Publish.objects.all() serializer_class = PublshSerializers
最终版:viewsets.ModelViewSet
urls.py:
url(r'^books/$', views.BookViewSet.as_view({"get":"list","post":"create"}),name="book_list"), url(r'^books/(?P<pk>\d+)$', views.BookViewSet.as_view({ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }),name="book_detail"),
views.py:
from rest_framework import viewsets
class BookViewSet(viewsets.ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializers