rest-framework项目示例
models.py
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
urls.py
from django.conf.urls import url from django.contrib import admin from api import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'books/$',views.BookView.as_view(),name="book_list"), url(r'publishes/$',views.PublishView.as_view(),name="publish_list"), url(r'books/(\d+)/$',views.BookDetailView.as_view(),name="book_detial"), url(r'publishes/(?P<pk>\d+)/$',views.PublishDetailView.as_view(),name="publish_detial"), ]
serializers组件
from rest_framework import serializers from ..models import * # 相当于是form的用法 # class Bookserializers(serializers.Serializer): # title = serializers.CharField(max_length=32) # price=serializers.IntegerField() # pub_date = serializers.DateField() # # publish = serializers.CharField() #form组件中对于外键关联的字段是使用ChoiceField,但在rest_framework中是使用的CharField # publish = serializers.CharField(source="publish.pk") #通过是用source来指定显示某个字段,如果不指定默认是显示的对象 # # authors = serializers.CharField(source="authors.all") # ''' # [ # { # "title": "python", # "price": 111, # "pub_date": "2018-04-08", # "publish": "1", # "authors": "<QuerySet [<Author: alex>, <Author: egon>]>" 显示的是字符串queryset这个,不是太好看,所以我们可以通过自定义方法来解决这个问题 # }, # ''' # # 针对多对多 # authors=serializers.SerializerMethodField() # def get_authors(self,obj): #固定用法,必须是get_多对多关系字段,需要传入一个对象,book对象 # temp=[] #返回结果是什么类型的可以自己定义 # for author in obj.authors.all(): # temp.append({ # "pk":author.pk, # "name":author.name # }) # return temp # 相当于是modelform的用法 class Bookserializers(serializers.ModelSerializer): # 重定义publish的显示,让它显示成url,一点就可以进入到和这个book关联的publish的信息,看到的是这样的形式的"publish": "http://127.0.0.1:8001/publishes/1/", ''' [ { "id": 1, "publish": "http://127.0.0.1:8001/publishes/1/", "authors": [ { "pk": 1, "name": "alex" }, { "pk": 2, "name": "egon" } ], "title": "python", "price": 111, "pub_date": "2018-04-08" }, ''' # publish=serializers.HyperlinkedIdentityField( # view_name="publish_detial", #url中的别名,这里指定url中的别名,是可以反向解析出url # lookup_field="publish_id",#出版社的url中的(\d+),指的是出版社的id # lookup_url_kwarg="pk" #分组命名中的名字 # # publishs/(?P<pk>\d+)/$ # ) class Meta: model = Book fields = "__all__" #取出所有字段的这种方式中多对多的字段中找出的是"authors": [1,2],里面装的是主键id,但是我不想使用这种方式,可以通过自定义的方法来解决 authors = serializers.SerializerMethodField() #自定义的方法可以覆盖掉多对多的显示方式,而使用自定义的显示字段"authors": {"pk": 1,"name": "alex"} def get_authors(self,obj): #固定用法,必须是get_多对多关系字段,需要传入一个对象,book对象 temp=[] #返回结果是什么类型的可以自己定义 for author in obj.authors.all(): temp.append({ "pk":author.pk, "name":author.name }) return temp class Publishserializers(serializers.ModelSerializer): class Meta: model=Publish fields="__all__"
views.py
from django.shortcuts import render, HttpResponse # Create your views here. from .models import * from rest_framework.views import APIView import json from rest_framework.response import Response from api.service.serializers import * # 把serializers封装成一个组件了,在api/service/serializers中 class BookView(APIView): def get(self, request, *args, **kwargs):#使用方式一,二,三的时候继承的类是View # # 方法一: # book_list=list(Book.objects.all().values("title","price"))#如果使用json来序列化查询出来的queryset,需要先把queryset转成list类型才能进行序列化,否则会出现报错TypeError: Object of type 'QuerySet' is not JSON serializable # ret=json.dumps(book_list) # return HttpResponse(ret) # 方法二: # book_list=Book.objects.all() # temp=[] # for book in book_list: # temp.append({"title":book.title,"price":book.price}) # return HttpResponse(json.dumps(temp)) # 方式三:使用serializers # from django.core import serializers # book_list=Book.objects.all() # ret= serializers.serialize("json",book_list) #将queryset进行序列化 # print(ret) # return HttpResponse(ret) # 方式四:使用rest_framework组件中的序列化queryset的方法,方法三和方法四都是序列化queryset,但是方法四中除了序列化,还有其他的方法 book_list = Book.objects.all() ret = Bookserializers(book_list, many=True, context={ 'request': request}) # 通过设置many=True,告诉Bookserializers,我传进去的是一个queryset,而不是一个对象,many默认是False # print(ret,type(ret)) #<class 'rest_framework.serializers.ListSerializer'> return Response(ret.data) # 调用data方法可以取到序列化之后的结果 # 提交请求数据 def post(self, request, *args, **kwargs): print(request.data) ret = Bookserializers(data=request.data, context={ 'request': request}) # context={'request': request}传入它的原因是,想要在查询到关联的外键的信息中是一个url, if ret.is_valid(): ret.save() # 和form组件的用法是一样的 return Response(ret.data) else: return Response(ret.errors) ''' class BookSerializers(serializers.Serializer): title=serializers.CharField(max_length=32) price=serializers.IntegerField() pub_date=serializers.DateField() publish=serializers.CharField(source="publish.pk") authors=serializers.CharField() 在get()方法中获取到的book_list是一个queryset,相当于是 temp=[] for book in book_list: #for循环出来的每一个对象都要经过BookSerializers,然后再把需要的信息.出来 temp.append({ "title": book.title, "price": book.price, "pub_date": book.pub_date, "publish": book.publish.pk, "authors": book.authors, }) 最终构造出来的数据类型 [ { "title": "python", "price": 111, "pub_date": "2018-04-08", "publish": "1", "authors": [ { "pk": 1, "name": "alex" }, { "pk": 2, "name": "egon" } ] },] ''' class PublishView(APIView): # def get(self, request, *args, **kwargs): publish_list = Publish.objects.all() # 将QuerySet序列化成json数据 bs = Publishserializers(publish_list, many=True, context={'request': request}) return Response(bs.data) # 提交数据请求 def post(self, request, *args, **kwargs): print(request.data) # 将json数据转换为Queryset bs = Publishserializers(data=request.data, context={'request': request}) if bs.is_valid(): bs.save() # 数据保存成功 return Response(bs.data) else: return Response(bs.errors) # 针对BOOK表某一个数据操作 查看,编辑,删除一本书 class PublishDetailView(APIView): # 查看一本书 def get(self, request, pk, *args, **kwargs): obj = Publish.objects.filter(pk=pk).first() if obj: bs = Publishserializers(obj, context={'request': request}) return Response(bs.data) else: return Response() # 编辑一本书 def put(self, request, pk, *args, **kwargs): # obj :编辑书籍对象 obj = Publish.objects.filter(pk=pk).first() bs = Publishserializers(data=request.data, instance=obj, context={'request': request}) if bs.is_valid(): bs.save() return Response(bs.data) else: return Response(bs.errors) # 删除一本书 def delete(self, request, pk, *args, **kwargs): Publish.objects.filter(pk=pk).delete() return Response() # 根据rest_framework的规则对于表中所有数据的查看的类中,只能有查看和保存数据的方法,所以需要设计一个针对表中某一个对象的操作方法 # 针对Book表某一个数据操作:查看,编辑,删除一本书 class BookDetailView(APIView): # 查看一本书 def get(self, request, pk, *args, **kwargs): obj = Book.objects.filter(pk=pk).first() if obj: # 判断obj是否存在,如果存在就返回一个序列化之后的json数据,否则就返回空白文本 bs = Bookserializers(obj) return Response(bs.data) else: return Response() # 编辑一本书 def put(self, request, pk, *args, **kwargs): # obj:编辑书籍对象 obj = Book.objects.filter(pk=pk).first() bs = Bookserializers(data=request.data, instance=obj) # 同modelform中的用法一样,把提交上来的数据传进去,还需要编辑的对象,是对哪一本书进行的操作 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() # 删除成功之后返回空白文本 # 如果我对关联表publish表进行操作的话,也是如同Book表一样,把Book的上面的两个类复制一份,然后改一下表名,再写一个publish的serliazer,显然会造成代码的重复 # 这里我们引入一个mixin,什么是mixin,mixin就是混合类 # ----------------------------------------------------------mixin-------------------------------------------------------------------------------- # from rest_framework import mixins # from rest_framework import generics # # class BookView(mixins.ListModelMixin, #根据字面意思也能知道ListModelMixin是查看数据的 # mixins.CreateModelMixin, #是保存数据的 # generics.GenericAPIView #GenericAPIView继承了APIView # ): # queryset = Book.objects.all() #必须查询出来的数据是queryset类型 # serializer_class = Bookserializers #serializer_class是源码中规定的,必须是这个名字,把自己定义的Bookserializers类赋值给serializer_class,用来做序列化操作 # # 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 BookDetailView( # mixins.RetrieveModelMixin, #对于一个对象的数据的查看 # mixins.DestroyModelMixin, #对于一个对象的数据的删除 # mixins.UpdateModelMixin, #对于一个对象的数据的编辑 # generics.GenericAPIView, #继承了APIView类 # ): # queryset = Book.objects.all() # serializer_class = Bookserializers # # def get(self,request,*args,**kwargs): # return self.retrieve(request,*args,**kwargs) #调用这个方法,会把我我传进去的queryset,serializer_class,经过处理,最终返回给我的是我要查询的这个对象的json数据 # def put(self,request,*args,**kwargs): # return self.update(request,*args,**kwargs) # def delete(self,request,*args,**kwargs): # return self.destroy(request,*args,**kwargs) # class PublishView(mixins.ListModelMixin, # mixins.CreateModelMixin, # generics.GenericAPIView): # # queryset = Publish.objects.all() # serializer_class = Publishserializers # # 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 PublishDetailView( # mixins.RetrieveModelMixin, # mixins.DestroyModelMixin, # mixins.UpdateModelMixin, # generics.GenericAPIView # ): # queryset = Publish.objects.all() # serializer_class = Publishserializers # # def get(self,request, *args, **kwargs): # return self.retrieve(request, *args, **kwargs) # # def delete(self,request, *args, **kwargs): # return self.destroy(request, *args, **kwargs) # # def put(self,request, *args, **kwargs): # return self.update(request, *args, **kwargs) # 如果要对publish进行操作,也是上面的方法,也是改一下表名,但是在调用的方法上也是代码的重复,这样是和继承APIView实现的方法没有多大差别,代码还是重复的使用 # 所以我们再引入一个类,可以解决上面的问题 # ------------------------------------------------------------使用通用的基于类------------------------------------------------ # from rest_framework import mixins # from rest_framework import generics # # class BookView(generics.ListCreateAPIView): # ''' # 点进去看源码,原来是和我们上面自己写的是一样的,这里只不过是给封装到了类里面 # class ListCreateAPIView(mixins.ListModelMixin, # mixins.CreateModelMixin, # GenericAPIView): # ..... # ''' # queryset = Book.objects.all() # serializer_class = Bookserializers # # # class BookDetailView(generics.RetrieveUpdateDestroyAPIView):#RetrieveUpdateDestroyAPIView里面包含了查,更新,和删除一个对象的功能 # queryset = Book.objects.all() # serializer_class = Bookserializers # # # # class PublishView(generics.ListCreateAPIView): # ''' # 点进去看源码,原来是和我们上面自己写的是一样的,这里只不过是给封装到了类里面 # class ListCreateAPIView(mixins.ListModelMixin, # mixins.CreateModelMixin, # GenericAPIView): # ..... # ''' # queryset = Publish.objects.all() # serializer_class = Publishserializers # # # class PublishDetailView(generics.RetrieveUpdateDestroyAPIView):#RetrieveUpdateDestroyAPIView里面包含了查,更新,和删除一个对象的功能 # queryset = Publish.objects.all() # serializer_class = Publishserializers # ps:有没有发现这种方法很简单呢