大家想一个问题现在只是一个Book,如果出现比如Author,Publisher等等,难道我们一直重复下去么 ?
比如我现在要写一个Author,从下面我们可以看出这是在重复造文字
urls.py
urlpatterns = [
url(r'^books/$',views.BookView.as_view()),
# 以pk命名是固定的
# 执行如下:(不在详细解析,可以跳过)
# view(request,pk=1)
# self.kwargs={"pk":1}
# queryset.get(**{"pk":1})
# queryset.get(pk=1)
url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
url(r'^authors/$',views.AuthorView.as_view()),
url(r'^authors/(?P<pk>\d+)/$',views.AuthorDetailView.as_view()),
]
views.py
from app01.models import Book
from app01.serializer import BookSerializers
class BookView(APIView):
def get(self,request):
book_list=Book.objects.all()
ps=BookSerializers(book_list,many=True)
# 序列化完成的数据
return Response(ps.data)
def post(self,request):
# 添加一条数据
# request.POST 在发JSON数据的时候是取不到值的,只有发urlecoding,orm-data才会有值
# REST已经对request再次封装了,发送JSON,urlecoding,form-data等常用等常用的数据都封装到data里了,这样就解决了request.POST 在发JSON数据的时候是取不到值的情况
print("data",request.data)
print("POST",request.POST)
# 生成一条记录
bs=BookSerializers(data=request.data)
# 校验成功后生成记录
if bs.is_valid():
bs.save()
# 把添加的数据序列化返回
return Response(bs.data)
else:
# 校验失败返回错误信息
return Response(bs.errors)
class BookDetailView(APIView):
def get(self,request,pk):
# 根据pk值获取数据库对应的一条对象
book_obj=Book.objects.filter(pk=pk).first()
# 序列化一个对象,默认就为False
bs=BookSerializers(book_obj,many=False)
return Response(bs.data)
def put(self,request,pk):
book_obj=Book.objects.filter(pk=pk).first()
# 更新一定要传两个值
# 第一个这次更新传进来的数据(data=request.data)
# 第二个要更新的对象(instance=book_obj)
bs=BookSerializers(data=request.data,instance=book_obj)
if bs.is_valid():
# 如果校验成功就updata
bs.save()
# 返回更新后的数据
return Response(bs.data)
else:
# 返回错误信息
return Response(bs.errors)
def delete(self,request,pk):
Book.objects.filter(pk=pk).delete()
return Response("OK")
# 以下基本都是重复上面的结构
from app01.models import Author
from app01.serializer import AuthorSerializers
class AuthorView(APIView):
def get(self,request):
author_list=Author.objects.all()
ser=AuthorSerializers(author_list,many=True)
return Response(ser.data)
def post(self,request):
ser=AuthorSerializers(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
class AuthorDetailView(APIView):
def get(self,request,pk):
author_obj=Author.objects.filter(pk=pk).first()
ser=AuthorSerializers(author_obj,many=False)
return Response(ser.data)
def put(self,request,pk):
author_obj=Author.objects.filter(pk=pk).first()
ser=AuthorSerializers(data=request.data,instance=author_obj)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
def delete(self,request,pk):
Author.objects.filter(pk=pk).delete()
return Response("OK")
第一种方法(把不同的请求分为5个类)
其实我们可以灵活的分成把不同请求分为5个类,类似于下面写的这种,别忘记python支持多继承,灵活继承-只继承他需要的
class LIST():
queryset=""
serialize_class=""
def list(self,request):
queryset=self.queryset
As=self.serialize_class(queryset(),many=True)
return Response(As.data)
class CREATE():
serialize_class = ""
def create(self,request):
As=self.serialize_class(data=request.data)
if As.is_valid():
As.save()
return Response(As.data)
else:
return Response(As.errors)
# --------------------
class AuthorView(APIView,LIST,CREATE):
queryset=Author.objects.all
serialize_class=AuthorSerializers
def get(self,request):
# author_list=Author.objects.all()
# ser=AuthorSerializers(author_list,many=True)
# return Response(ser.data)
return self.list(request)
def post(self,request):
# ser=AuthorSerializers(data=request.data)
# if ser.is_valid():
# ser.save()
# return Response(ser.data)
# else:
# return Response(ser.errors)
return self.create(request)
# .......... 按照这种方法,在写三个加id参数的,这里就不一一写了,因为REST有跟这个类似的封装............
以下就是REST封装的
from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin
Author为例
from app01.models import Author
from app01.serializer import AuthorSerializers
from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin
from rest_framework import generics
# generics.GenericAPIView 继承的是APIView,在里边又定义了以下五个方法内需要的参数
class AuthorView(ListModelMixin,CreateModelMixin,generics.GenericAPIView):
# 以下这些格式是变量等都是固定的
queryset=Author.objects.all()
serializer_class=AuthorSerializers
def get(self,request):
return self.list(request)
def post(self,request):
return self.create(request)
class AuthorDetailView(DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin,generics.GenericAPIView):
# 以下这些格式是变量等都是固定的
queryset=Author.objects.all()
serializer_class=AuthorSerializers
def get(self,request, *args, **kwargs):
# 看一下对应方法源码里边有return Response就是我们这要return的
return self.retrieve(request, *args, **kwargs)
def put(self,request, *args, **kwargs):
# 看一下对应方法源码里边有return Response就是我们这要return的
return self.update(request, *args, **kwargs)
def delete(self,request, *args, **kwargs):
# 看一下对应方法源码里边有return Response就是我们这要return的
return self.destroy(request, *args, **kwargs)
第二种方法(把5个类根据是否有id参数封装成两个类)
view.py
from app01.models import Author
from app01.serializer import AuthorSerializers
from rest_framework import generics
class AuthorView(generics.ListCreateAPIView):
# 以下这些格式是变量等都是固定的
queryset=Author.objects.all()
serializer_class=AuthorSerializers
class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
# 以下这些格式是变量等都是固定的
queryset=Author.objects.all()
serializer_class=AuthorSerializers
继承类源码简单分析
# generics.ListCreateAPIView) 继承了原先三个类
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
"""
Concrete view for listing a queryset or creating a model instance.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
# generics.RetrieveUpdateDestroyAPIView 继承了原先四个类
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
"""
Concrete view for retrieving, updating or deleting a model instance.
"""
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 patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
第三种方法(终极)
上边的view.py
可以看出来还有重复的部分,那我们就封装到一个类里面去,那我们的想一个问题了view.py
怎么写?
如:两个get请求一个视图处理怎么区分;加参数与不加参数
authors为例:
对应的请求执行对应的方法,仔细看key对应的value,value跟第一种方法要return返回的方法执行的方法变量一致 (第一种方法(把不同的请求分为5个类)),以后用的最多的也是第一种和第三种
urls.py
urlpatterns = [
# 执行get请求执行list方法,post执行create方法
url(r'^authors/$',views.AuthorModelView.as_view({"get":"list","post":"create"})),
# 执行get请求执行retrieve方法,put执行update方法,delete请求destroy
url(r'^authors/(?P<pk>\d+)/$',views.AuthorModelView.as_view({"get":"retrieve","put":"update","delete":"destroy"})),
]
serializer.py
from app01.models import Author
class AuthorSerializers(serializers.ModelSerializer):
class Meta:
model=Author
field
views.py
from app01.models import Author
from app01.serializer import AuthorSerializers
from rest_framework.viewsets import ModelViewSet
class AuthorModelView(ModelViewSet):
# 以下这些格式是变量等都是固定的
queryset=Author.objects.all()
serializer_class=AuthorSerializers
源码简单分析
ModelViewSet
# ModelViewSet继承了5个不同请求方法类
# 主要区别在于ModelViewSet继承了GenericViewSet而不是第一种与第二种类继承的GenericAPIView
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `create()`, `retrieve()`, `update()`,
`partial_update()`, `destroy()` and `list()` actions.
"""
pass
GenericViewSet
又干了什么呢 ?
Django一启动走到了view方法-return csrf_exempt(view),用户一访问执行view()
# GenericViewSet 他继承了第一种与第二种类继承的GenericAPIView
# 所以区别就在与ViewSetMixin
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
"""
The GenericViewSet class does not provide any actions by default,
but does include the base set of generic view behavior, such as
the `get_object` and `get_queryset` methods.
"""
pass
# ViewSetMixin 重写了as_view方法,
class ViewSetMixin(object):
# 看这神奇的注释,它简单的解释了一切
"""
这是神奇的。
覆盖'.as_view()',使其具有执行的' actions '关键字
将HTTP方法绑定到资源上的操作。
例如,创建绑定“GET”和“POST”方法的具体视图
到“列表”和“创建”动作……
这就是告诉你怎么用这个类,就是给urls.py,as_view加参数
get不要在执行get请求执行list方法,post执行create方法
view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
"""
"""
This is the magic.
Overrides `.as_view()` so that it takes an `actions` keyword that performs
the binding of HTTP methods to actions on the Resource.
For example, to create a concrete view binding the 'GET' and 'POST' methods
to the 'list' and 'create' actions...
view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
"""
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
cls.suffix = None
cls.detail = None
# ..............................................等
def view(request, *args, **kwargs):
self = cls(**initkwargs)
# 我们还存储请求方法到动作的映射,
# 以便我们以后可以设置action属性.
# 如. 对传入的GET(GET=self.action)请求的操作`self.action = 'list'`
self.action_map = actions
#将方法绑定到操作
# 这一点与标准视图不同
# actions相当于urls.py,as_view传进来的参数
# actions={"get":"list","post":"create"}
# actions={"get":"retrieve","put":"update","delete":"destroy"}
for method, action in actions.items():
handler = getattr(self, action)
setattr(self, method, handler)
# 上边的for循环相当于
# self.get=self.list self.post=self.create
# 另一种URL时:self.get=self.retrieve self.put=self.update self.delete=self.destroy
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# And continue as usual
return self.dispatch(request, *args, **kwargs)
# ..............................................等
view.cls = cls
view.initkwargs = initkwargs
view.suffix = initkwargs.get('suffix', None)
view.actions = actions
return csrf_exempt(view)
总结
作为数据接口:第三种最合适-写到一个类里面
作为非数据接口:第一种最合适-写到5个类里面去-如:登陆
网友评论