序列化
序列化:转化数据和校验数据(提交数据时校验数据类型)
开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json
之类的表示形式的方式。我们可以通过声明与Django forms非常相似的序列化器(serializers)来实现。
class Book(models.Model): title=models.CharField(max_length=32) price=models.IntegerField() pub_date=models.DateField() publish=models.ForeignKey(to="Publish") authors=models.ManyToManyField(to="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 class User(models.Model): user=models.CharField(max_length=32) pwd=models.CharField(max_length=32) user_type=models.IntegerField(choices=((1,"普通用户"),(2,"VIP用户"),(3,"SVIP用户"))) def __str__(self): return self.user class UserToken(models.Model): user=models.OneToOneField(to="User") token=models.CharField(max_length=128) def __str__(self): return self.token
1.使用serializers(用法类似与form组件)
from rest_framework import serializers #为Book表定制序列化组件 #使用Serializer class BookSerializers(serializers.Serializer):
#普通字段 title=serializers.CharField(max_length=32) price=serializers.IntegerField() pub_date=serializers.DateField() # 一对多使用Charfiled类型,source更改显示的字段 publish=serializers.CharField(source="publish.email") # 多对多字段 authors=serializers.SerializerMethodField() def get_authors(self,obj):#obj为book对象 temp=[] for author in obj.authors.all(): temp.append({"id":author.id,"name":author.name}) return temp
2.使用ModelSerializer(使用方法类似与modelform组件)
class BookModelSerializer(serializers.ModelSerializer): class Meta: model=Book fields="__all__" # exclude=["authors",] #显示authors以外的字段(单独使用) # authors=serializers.SerializerMethodField() #可以和fields=“__all__”配合使用 # def get_authors(self,obj): # temp=[] # for author in obj.authors.all(): # temp.append({"id":author.id,"name":author.name}) # return temp
视图(views)
class BookViews(APIView):
pass
class BookViews(其他类):
queryset=Book.objects.all() #必须写queryset,不写有可能报错(源码断言处理)
断言:
assert self.queryset is not None, ( "'%s' should either include a `queryset` attribute, " "or override the `get_queryset()` method." % self.__class__.__name__ )
1.继承APIView类(继承了View)
处理Book表全部信息,查看、添加 class BookViews(APIView): def get(self,request,*args,**kwargs): book_list=Book.objects.all() # querset数据转化为json数据 bs=BookModelSerializer(book_list,many=True) #queryset时,many=True;单个对象时,默认many=False # bs.data序列化后的数据[{},{}] return Response(bs.data) def post(self,request,*args,**kwargs): # 获取前端提交的数据 obj=request.data #json数据转化为queryset数据 bs=BookModelSerializer(data=obj) # 验证 if bs.is_valid(): bs.save() # 显示json数据 return Response(bs.data) else: # 显示错误信息 return Response(bs.errors) # 处理指定book的信息,查看、编辑、删除 class BookDetailViews(APIView): def get(self,request,pk,*rags,**kwargs): book_obj=Book.objects.filter(pk=pk).first() if not book_obj: return Response("没有这条记录") bs=BookModelSerializer(book_obj) return Response(bs.data) def put(self,request,pk,*rags,**kwargs): # 获取编辑后的json数据 obj=request.data book_obj=Book.objects.filter(pk=pk).first() # 将data的json数据转换为queryset(book_obj)数据 bs=BookModelSerializer(data=obj,instance=book_obj) if bs.is_valid(): bs.save() return Response(bs.data) else: return Response(bs.errors) def delete(self,request,pk,*args,**kwargs): Book.objects.filter(pk=pk).delete() return Response("删除成功")
2.使用Mixin类(ListModelMixin等中实现了增删改查方法)
from rest_framework import mixins from rest_framework import generics class BookViews(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView): queryset = Book.objects.all() serializer_class = BookModelSerializer # 继承mixins.ListModelMixin def get(self,request,*args,**kwargs): return self.list(request, *args, **kwargs) # 继承mixins.CreateModelMixin def post(self,request,*args,**kwargs): return self.create(request,*args,**kwargs) class BookDetailViews(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView): # lookup_field = 'pk' 找到url(r'^books/(?P<pk>d+)/$', views.BookDetailViews.as_view())generics.GenericAPIView中默认设置好了,先queryset查询再进行过滤 queryset = Book.objects.all() serializer_class = BookModelSerializer 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)
3.使用通用的基于类视图
from rest_framework import generics
ListCreateAPIView继承mixins.ListModelMixin,mixins.CreateModelMixin,GenericAPIView class BookViews(generics.ListCreateAPIView): queryset = Book.objects.all() serializer_class = BookModelSerializer class BookDetailViews(generics.RetrieveUpdateDestroyAPIView): queryset = Book.objects.all() serializer_class = BookModelSerializer
4.终极版viewsets.ModelViewSet(重新定义了as_view())
###############终极版viewsets.ModelViewSet########### from rest_framework import viewsetsclass BookViewsSet(viewsets.ModelViewSet): queryset = Book.objects.all() serializer_class = BookModelSerializer
urls.py
url(r'^books/$',views.BookViewsSet.as_view({"get":"list","post":"create"})),
url(r'^books/(?P<pk>d+)/$',views.BookViewsSet.as_view({"get":"retrieve","put":"update","delete":"destr
ModelViewSet类的继承关系(自己有的用自己的,自己没有的用父类的)
解释器(parser)
根据请求头content_type对应的的解析器类型进行请求体处理
urlencoded 对应 格式一:name=alex&age=123&email=131232 json 对应 格式二:{name:'xx',age:'xxx'}
1、Django中的request类:
from django.core.handlers.wsgi import WSGIRequest
只是对 "multipart/form-data"(上传文件)和"application/x-www-form-urlencoded"(如form表单)进行了处理,其他类型的请求头,都要进行解码和反序列化(json.loads.(request.body.decode="utf8"))
只有在content_type="multipart/form-data"或"application/x-www-form-urlencoded"时,request.POST中才有数据request.body中有元数据
2、rest_frmaework中的request类:
from rest_framework.parsers import JSONParser,FileUploadParser,FormParser,MultiPartParser
rest_frmaework:中将解析器的种类扩大有 JSONParser,FileUploadParser,FormParser,MultiPartParser所有数据都在request.data中
个别特殊的值可以通过request._request 来进行获取 因为它对Django中的request进行了二次封装
第一次:
头:
content-type: application/x-www-form-urlencoded
体:
k1=v1&k2=v2
request.data 接收到的是QueryDict类型
第二次:
头:
content-type: application/json
体:
{"k1":"v1","k2":"v2"}
reuqest.data 接收到的是dict类型
在rest_frmaework中:
局部使用parser:
views.py
from rest_framework.parsers import JSONParser,FormParser,FileUploadParser,MultiPartParser 默认使用JSONParser,FormParser
class BookViewsSet(viewsets.ModelViewSet): #重新定义了as_view()
# 解析器
parser_classes=[JSONParser,FileUploadParser,FormParser,MultiPartParser]
queryset = Book.objects.all()
serializer_class = BookModelSerializer
全局使用parser:
settings.py
REST_FRAMEWORK={# 解析器 "DEFAULT_PARSER_CLASSES":["rest_framework.parsers.JSONParser","rest_framework.parsers.FileUploadParser",] }
分页(page)
一、自定义页码分页
1.自定义list()分页
view.py
from rest_framework.pagination import PageNumberPagination class BookViewsSet(viewsets.ModelViewSet): #重新定义了as_view() queryset = Book.objects.all() serializer_class = BookModelSerializer #自定义list ,分页 def list(self,request,*args,**kwargs): book_list=Book.objects.all() print(book_list) pnp=PageNumberPagination() pager_book=pnp.paginate_queryset(queryset=book_list,request=request,view=self) print("pager_book",pager_book) # 序列化分页后的数据 bs=BookModelSerializer(pager_book,many=True) return pnp.get_paginated_response(bs.data)
settings.py
REST_FRAMEWORK={ # 自定义list()分页,每页显示的个数 "PAGE_SIZE": 2 }
2.自定义页码分页
pageing.py
from rest_framework.pagination import PageNumberPagination class PageBook(PageNumberPagination): page_size = 1 page_query_param = 'page' page_size_query_param = "size" max_page_size =1
views.py
class BookViewsSet(viewsets.ModelViewSet): #重新定义了as_view() # 分页 pagination_class=PageBook queryset = Book.objects.all() serializer_class = BookModelSerializer
二、按照索引和每页显示的个数
pageing.py
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination #用法http://127.0.0.1:8001/books/?offset=1&limit=2 根据起始索引和每页显示的个数 class PageBook(LimitOffsetPagination): # 默认每页显示的数据条数 default_limit = 2 # URL中传入的显示数据条数的参数 limit_query_param = 'limit' # URL中传入的数据位置的参数 offset_query_param = 'offset' # 最大每页显得条数 max_limit = None
views.py
class BookViewsSet(viewsets.ModelViewSet): #重新定义了as_view()
# 分页
pagination_class=PageBook
queryset = Book.objects.all()
serializer_class = BookModelSerializer
三、游标分页
pageing.py
# 游标分页 对cursor进行加密,只能通过指定的url进行访问(只能通过图片中的url访问) class PageBook(CursorPagination): # URL传入的游标参数 cursor_query_param = 'page' # 默认每页显示的数据条数 page_size = 2 # URL传入的每页显示条数的参数 page_size_query_param = 'page_size' # 每页显示数据最大条数 max_page_size = 1000 # 根据ID从大到小排列 ordering = "id"
views.py
class BookViewsSet(viewsets.ModelViewSet): #重新定义了as_view() # 分页 pagination_class=PageBook queryset = Book.objects.all() serializer_class = BookModelSerializer
路由系统
1.自定义路由
http://127.0.0.1:8001/books/?format=json 浏览器中可以直接访问json数据
url(r'^books/$',views.BookViewsSet.as_view({"get":"list","post":"create"})),
#http://127.0.0.1:8001/books.json 或 http://127.0.0.1:8001/books/?format=json 浏览器中可以直接访问json数据 url(r'^books.(?P<format>[a-z0-9]+)$',views.BookViewsSet.as_view({"get":"list","post":"create"})),
2.自动生成url
# 自动生成url from django.conf.urls import url,include from api import views from rest_framework import routers router = routers.DefaultRouter() router.register(r'books', views.BookViewsSet) urlpatterns = [ # 自动生成url url(r'^',include(router.urls)), ]
响应器
根据 用户请求URL 或 用户可接受的类型,筛选出合适的 渲染组件。
用户请求URL:
http://127.0.0.1:8000/books/?format=json
http://127.0.0.1:8000/books.json
http://127.0.0.1:8000/books
用户请求头:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
from rest_framework.renderers import BrowsableAPIRenderer,JSONRenderer,AdminRenderer,HTMLFormRenderer,TemplateHTMLRenderer
以下访问urls.py都一样
urlpatterns = [ url( # http://127.0.0.1:8001/books/?format=json或http://127.0.0.1:8001/books.json #浏览器中可以直接访问json数据 url(r'^books.(?P<format>[a-z0-9]+)$',views.BookViewsSet.as_view({"get":"list","post":"create"})), ]
1. 访问json
urls.py:
http://127.0.0.1:8000/books/?format=json http://127.0.0.1:8000/books.json http://127.0.0.1:8000/books
views.py
class BookViewsSet(viewsets.ModelViewSet):
# 响应器
renderer_classes=[JSONRenderer]
queryset = Book.objects.all()
serializer_class = BookModelSerializer
2.表格
urls.py:
http://127.0.0.1:8000/books/?format=admin
http://127.0.0.1:8000/books.admin
http://127.0.0.1:8000/books
views.py
class BookViewsSet(viewsets.ModelViewSet):
# 响应器
renderer_classes=[AdminRenderer]
queryset = Book.objects.all()
serializer_class = BookModelSerializer
3.form表单
urls.py:
http://127.0.0.1:8000/books/?format=form http://127.0.0.1:8000/books.form http://127.0.0.1:8000/books
views.py
class BookViewsSet(viewsets.ModelViewSet):
# 响应器
renderer_classes=[HTMLFormRenderer]
queryset = Book.objects.all()
serializer_class = BookModelSerializer
4.自定义显示模板
urls.py:
http://127.0.0.1:8000/books/?format=html http://127.0.0.1:8000/books.html http://127.0.0.1:8000/books
views.py
class BookViewsSet(viewsets.ModelViewSet):
# 响应器
renderer_classes=[TemplateHTMLRenderer,]
def get(self, request, *args, **kwargs): book_list = Books.objects.all() bs = BookSerializer(instance=book_list, many=True) return Response(bs.data, template_name='books.html')
books.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 {{ title }} 9 {{ price }}11 </body> 12 </html>
3.form表单
urls.py:
http://127.0.0.1:8000/books/?format=api http://127.0.0.1:8000/books.api http://127.0.0.1:8000/books
views.py
class BookViewsSet(viewsets.ModelViewSet):
# 响应器
renderer_classes=[renderer_classes=[HTMLFormRenderer]]
queryset = Book.objects.all()
serializer_class = BookModelSerializer
待续