Django的CBV
dfr基于CBV比纯粹的CBV功能更加强大,继承于django.views中的View
在路由的最后一定要添加/否则会重定向到get请求中。
源码都是基于以下的所以先看
继承类中的函数反射
class Animal(object):
def __init__(self, name, age, func_str):
self.name = name
self.age = age
func = getsttr(self,'sleep') ==>self.sleep()
func()
class Dog(Animal):
def wangwang(self):
print("汪汪叫")
def sleep(self):
print("睡觉")
alex = Dog("alex", 35, 'sleep') #指定调用sleep函数
as_views()源码,调用的本质还是返回一个view
只保留关键代码:
@classonlymethod #只允许类方法
def as_view(cls, **initkwargs): #cls:当前调用的类
def view(request, *args, **kwargs):
self = cls(**initkwargs) #实例化当前类
return self.dispatch(request, *args, **kwargs) #dispatch分发路由,来一个处理一个
return view #返回视图
def dispatch(self, request, *args, **kwargs):
''' 此处的getattr与上面继承的那个例子中的getsttr用法类似
self:当前的类
request.method.lower():当前请求的方法将其转换为小写,请求的方法就是那几个GET POST PUT...
'''
handler = getattr( self, request.method.lower())
return handler(request, *args, **kwargs) #将结果返回,此时就能和view一样接收到请求了
一旦用户访问book,比如用get请求访问/book/
get请求访问=>view() =>return self.dispatch() =>return get()
一、APIview完成增删改查
APIview是DRF的核心,相较于View添加了什么呢?
剩下的部分和cbv中的介绍是相同的
留下重要部分:
1.重写了as_view方法
2.APIView重新构建了request请求,这个请求发过来的数据均为JSON!!!(重要)
获取原生的reques为request._request
@classonlymethod #只允许类方法
class APIView:
def as_view(cls, ): #cls:当前调用的类
view = super().as_view()
return view
class View:
def as_view(cls):
def view(request,:
self = cls(**initkwargs) #实例化当前类
return self.dispatch(request, *args, **kwargs) #dispatch分发路由,来一个处理一个
return view #返回视图
def dispatch(self, request, *args, **kwargs):
'''1.APIView中和View不一样之处则是它重新构建了新的request对象
2.初始化:认证、权限、限流组件三件套
'''
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.initial(request,*args,**kwargs)
handler = getattr( self, request.method.lower())
return handler(request, *args, **kwargs) #将结果返回,此时就能和view一样接收到请求了```
最重要之一序列化器-Serializer
序列化:将数据库的数据输出
反序列化:将数据存入数据库
流程
1.设计Model
class Book(models.Model):
title = models.CharField(max_length=32,verbose_name='书籍名称')
price = models.IntegerField(verbose_name='价格')
2.针对模型设计序列化器
class BookSerializers(serializers.Serializer):
title = serializers.CharField(max_length=3)
price = serializers.IntegerField()
3.做相应操作
对单条和全部数据做操作时需要区分开来
1)get获取全部的数据,参数:instance(需要序列化的对象)many(是否序列化全部数据)
def get(self, request): #序列化操作
book_list = Book.objects.all()
serializer = BookSerializers(instance=book_list,many=True)
print(serializer.data)
return HttpResponse(serializer.data)
2)post传入单条数
def post(self,request): #反序列化操作
print('data',request.data)
serializer = BookSerializers(data=request.data)
#校验数据 首先校验字段是否存在,字段是否为所设定的数据类型,是否符合所设定的长度
if serializer.is_valid(): #符合规则的数据都会放入到clearn数据中返回布尔值,只有所有字段都通过校验才返回True
new_book = Book.objects.create(**serializer.validated_data)
return Response(serializer.data)
else:
return Response(serializer.errors) #返回错误信息
增查 (改删查(单条))针对单条的操作需要在url定义时区分开来
例如:
update和create的区别则是是否传入instance,当为update方法时则传入经过校验的validated_data数据
直接用ModelSerializer实现序列化可以实现两项功能
1.字段的序列化
2.数据的改和查,写的逻辑更加的详细,能够完成多对一、多对多的逻辑。
二、GenericaAPI 实现增删改查
通用视图类,继承自APIView,主要增加了操作序列化器和数据库查询的方法,作用时为下面Mixin扩展类的执行提供属性和方法,具体有:
(1)get_serializer_class(self) 获取序列化的类
(2)get_serializer(self,args,*kwargs)获取序列化对象
(3)get_queryset(self) 返回视图的查询集
(4)get_object(self) 返回详细视图所需的模型类数据对象
from rest_framework.generics import GenericAPIView
class PublishSerializers(serializers.ModelSerializer):
class Meta:
model = Publish
fields = '__all__'
class PublishView(GenericAPIView):
queryset = Publish.objects.all() # 固定的获取所有的queryset
serializer_class = PublishSerializers # 指定固定的序列化器
def get(self, request):
serializer = self.get_serializer(instance=self.get_queryset(), many=True) # 拿到的就是序列化对象
return Response(serializer.data)
(感觉只是一个get还没能非常体现出它的简洁性)可能是自己没悟透
往后的查询就只需要更改模型和序列化器这两个变量就可以了(悟了悟了)
来对比一下APIView和GenericAPI在针对不同的模型做相同操作时需要变动的地方:
APIView每一个操作逻辑中的模型类和序列化器都需要修改
GenericAPI只需要修改最初始的queryset和serializer_class字段,后续的操作逻辑中均不用修改。
哇啊哇,不学不知道,学了吓一跳,之前的序列化和现在学的对比代码量少了太多,一个查询功能的代码量相当于现在的查询和添加的代码量。真行!
1.查询单条
使用GenericAPIView查询单条的操作,需要注意匹配路由时的有名分组细节,意思就是在路由设置时需要设置关键字参数,传递给对应的视图函数。以下两种方式皆可
class PublishDetailView(GenericAPIView):
queryset = Publish.objects.all()
serializer_class = PublishSerializers
def get(self, request, pk):
# book = Book.objects.get (pk=id)
# serializer = BookSerializers(instance=book, many=False)
serializer = self.get_serializer(instance=self.get_object(), many=False)
return Response(serializer.data)
2.修改单条数据
def put(self, request, pk):
print('data:', request.data)
serializer = self.get_serializer(instance=self.get_object(), data=request.data) # 针对某个对象做修改
if serializer.is_valid():
serializer.save() # 是创建还是更新的操作就判断是否有传入一个实例,传入实例则为更新
else:
return Response(serializer.errors)
return Response()
对比一下最开始学的修改单条数据的方法,简直省事太多!
3.删除数据
def delete(self, request, pk):
self.get_object().delete()
return Response('删除成功')
三、MixIn混合类
这个更简单!比昨天的又又又少了代码了,就是不知道这样的话对于数据的校验方便不,不过昨天可以重写数据校验返回数据
一页截图就完成了,返回的均为混合类所封装好的功能,这些功能就是在GenerialView缩写好的哪些逻辑,一下更新某条数据的源码。
接下来做数据验证。
要注意重写的名字需要是validate_想要验证的字段名,这样才可以验证成功否则就无法正常的进行验证。调用结果如下:
四、基于MixIn的再封装(直接两行完成)
真的有意思啊,django你是真的行。增删改查查就这么几行数据!可能在操作里面用不着做每次都会做这几样,可以自己灵活搭配!!
不能再封装了吧!课程都是看一个Bazinga老师讲的,我也不知道到底谁发布的才是正主XD,反正讲得真的太好了!!
五、ViewSet路由分发
不用在同时有两个get请求的时候多写两个类进行分别响应操作了,可以使用viewset自己会进行视图的分发。
路由的定义
在as_view({})中写好所绑定好的请求和功能之间的关系,当发起某一个请求的时候则会对应的响应。比如当发出单条的请求的时候只需要跟上pk值即可。
主要的分发逻辑为如下:
接受到的对象为:{‘get’:‘get_all’,‘post’:‘add_object’}
将action取出后使用getattr将其转变为handler可以调用的类型。将其传过去则名字和方法就一一对应可以调用了。
上面只是一个匹配路由的逻辑,当然一路走来那么多封装肯定不会让我们自己再写那么多的逻辑,直接就调用封装在MixIn类中的ListModelMixin、CreateModelMixin的那个五类,类里面就有增删改查的几个方法,如CreateModelMixin的详细如下所示:
有一个create,那么在路由匹配的时候就直接相互匹配就可以了。
这下全封装完了,这样封装对于大多数情况下都很方便,有些地方需要重写。
六、路由组件
这是最后一点了,将路由配置的地方也加简洁一下,这样可以不用每次都去输入它的五个方法。