DRF的视图

APIView

我们django中写CBV的时候继承的是View,rest_framework继承的是APIView,那么他们两个有什么不同呢~~~

urlpatterns = [
    url(r'^book$', BookView.as_view()),
    url(r'^book/(?P<id>\d+)$', BookEditView.as_view()),
]

我们可以看到,不管是View还是APIView最开始调用的都是as_view()方法~~那我们走进源码看看~~

我们能看到,APIView继承了View, 并且执行了View中的as_view()方法,最后把view返回了,用csrf_exempt()方法包裹后去掉了csrf的认证。

那我们点击进View中查看的as_view()方法做了什么~

我们看到了~在View中的as_view方法返回了view函数,而view函数执行了self.dispatch()方法~~但是这里的dispatch方法应该是我们APIView中的~~

我们去initialize_request中看下把什么赋值给了request,并且赋值给了self.request, 也就是我们在视图中用的request.xxx到底是什么~~

点进Request类中看到,这个方法返回的是Request这个类的实例对象~~我们注意我们看下这个Request类中的第一个参数request,是我们走我们django的时候的原来的request~

我们看到了,这个Request类把原来的request赋值给了self._request, 也就是说以后_request是我们老的request,新的request是我们这个Request类~~

那我们继承APIView之后请求来的数据都在哪呢~~

我们用了rest_framework框架以后,我们的request是重新封装的Request类~

request.query_params 存放的是我们GET请求的参数

request.data 存放的是我们所有的数据,包括post请求的以及put,patch请求~~~

相比原来的django的request,我们现在的request更加精简,清晰了~~~

现在我们知道了APIView和View的一些区别~~当然还有~~后面我们还会说~~

我们写的视图可能对多个表进行增删改查,就导致我们的视图特别多重复的代码~~

那么我们尝试着来进行封装一下~~

未封装版本

此时只是一本书的增删盖查查,假如说现有40个表呢?想到类的多态,封装和继承了没?

from rest_framework.views import APIView
from rest_framework.response import Response
from djangoDemo.models import Book
from .serializers import BookSerializer # 查看所有的book
class BookView(APIView): def get(self, request):
book_queryset = Book.objects.all()
# 用序列化器进行序列化 能够匹配的就进行序列化 匹配不上的就抛弃
ser_obj = BookSerializer(book_queryset, many=True)
return Response(ser_obj.data) def post(self, request):
# 确定数据类型以及数据解构
# 对前端传过来的数据进行校验(前部数据不可信!)(序列化去做)
book_obj = request.data # 相当于request.POST
# print(book_obj)
ser_obj = BookSerializer(data=book_obj) # 反序列化
if ser_obj.is_valid(): # 如果检验成功
ser_obj.save() # 要调用create方法 需要去serializer中去写
return Response(ser_obj.validated_data) # 返回一个 ser_obj.validated_data 检验通过的数据 return Response(ser_obj.errors) # 没验证成功 就返回 ser_obj.errors 错误信息 # 查看单条book信息
class BookEditView(APIView): def get(self, request, id):
book_obj = Book.objects.filter(id=id).first()
ser_obj = BookSerializer(book_obj)
return Response(ser_obj.data) def put(self, request, id):
book_obj = Book.objects.filter(id=id).first()
ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
# 对象的本身传进去, 数据传进去,部分校验=true
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.validated_data) # 返回更新的内容
return Response(ser_obj.errors) # 返回错误信息 def delete(self, request, id):
book_obj = Book.objects.filter(id).first()
if not book_obj:
return Response("您删除的书籍不存在")
return Response("")

APIView视图

from rest_framework import serializers
from djangoDemo.models import Book class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32) class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=32) # 自己定义的校验方法需要配合字段使用 在字段中加入 validators=[my_validate, ]
def my_validate(value):
print(333)
if "敏感词汇" in value.lower():
raise serializers.ValidationError("含有敏感词汇")
return value # class BookSerializer(serializers.Serializer):
# id = serializers.IntegerField(required=False) # required=False 序列化去验证,反序列化不校验
# title = serializers.CharField(max_length=32, validators=[my_validate, ])
# pub_time = serializers.DateField()
# category = serializers.CharField(source="get_category_display", read_only=True) # source 后边参数都会当成ORM去操作
# post_category = serializers.IntegerField(write_only=True) # write_only=True正序不用,反序用
#
# publisher = PublisherSerializer(read_only=True)
# # 内部通过外键关系的id找到了publisher_obj
# # 然后实例化并传参 PublisherSerializer (publisher_obj)
# publisher_id = serializers.IntegerField(write_only=True) # 只有反序使用
#
# authors = AuthorSerializer(many=True, read_only=True) # read_only = True 正序使用 反序不使用
# author_list = serializers.ListField(write_only=True)
#
# def create(self, validated_data):
# # validated_data 校验通过通过的数据 就是book_obj
# # 通过ORM操作给 book表增加数据
# print(validated_data)
# book_obj = Book.objects.create(title=validated_data["title"],
# pub_time=validated_data["pub_time"],
# category=validated_data["post_category"],
# publisher_id=validated_data["publisher_id"])
# book_obj.authors.add(*validated_data["author_list"]) # 添加对应的作者
# print(book_obj)
#
# return book_obj # 返回对象 不返回就报错
#
# def update(self, instance, validated_data):
# # instance 更新的book_obj 对象
# # validated_data 校验通过的数据
# # ORM做更新操作
# instance.title = validated_data.get("title", instance.title) # ( 拿到传过来的值,拿不到就用book对象自身的值)
# instance.pub_time = validated_data.get("pub_time", instance.pub_time) # 同理
# instance.category = validated_data.get("post_category", instance.category)
# instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
# if validated_data.get("author_list"): # 取到作者(多对多)对应的值后
# instance.authors.set(validated_data["author_list"]) # 设置对应作者的关系表的值
# instance.save() # 保存下所有的值
# return instance # 返回book对象
#
# # 暴露出来的钩子函数 单字段的校验
# def validate_title(self, value):
# print(1111)
# # vlaue 就是title的值,对value处理
# if "python" not in value.lower():
# raise serializers.ValidationError("title字段必须有python")
# return value
#
# # 多字段的钩子函数
# def validate(self, attrs):
# print(2222)
# # attrs 字典有你传过来的所有的字段
# print(attrs)
# if "python" in attrs["title"].lower() or attrs["post_category"] == 1:
# return attrs
# else:
# raise serializers.ValidationError("分类或标题不符合要求") class BookSerializer(serializers.ModelSerializer):
# category_display = serializers.SerializerMethodField()
publisher_info = serializers.SerializerMethodField(read_only=True) # 正序校验的字段
authors_info = serializers.SerializerMethodField(read_only=True) # 正序验证的字段 # def get_category_display(self, obj):
# # obj 就是序列化的每个book对象
# # return "ok" # 此时所有的类别就是 ok(可以实现自定义展示)
# return obj.get_category_display() def get_authors_info(self, obj):
authors_querset = obj.authors.all() # 拿到多对多所有作者对象
# 返回作者id和name
return [{"id": author.id, "name": author.name} for author in authors_querset] def get_publisher_info(self, obj):
# obj book对象
publisher_obj = obj.publisher # 拿到外键对应的的出版社对象
return {"id": publisher_obj.id, "title": publisher_obj.title} # 返会自定义的id和名字 class Meta:
model = Book
fields = "__all__"
# depth 会让所有的外键关系字段变成read_only = True
# depth = 1 # 外键的深度 ,外键的所有字段(比较冗余)(开发不常用,一般自己构造)
extra_kwargs = {"publisher": {"write_only": True}, "authors": {"write_only": True}} # 反序校验的字段

serializers序列化文件

第一次封装

其实想想发现代码逻辑都相同,不同有两点

  1.表名不同,2.序列化类不同

from rest_framework.views import APIView
from rest_framework.response import Response
from djangoDemo.models import Book
from .serializers import BookSerializer # 第一次封装 定义一个通用类
class GenericAPIView(APIView):
queryset = None
Serializer_class = None # 定义一个获取对象方法
def get_queryset(self):
return self.queryset.all() # 不加all() django会吧queryset集合放到缓存中要通过加上.all()才能调用 def get_serializer(self, *args, **kwargs):
return self.Serializer_class(*args, **kwargs) # 直接返回一个实例化对象 # 展示类
class ListModelMixin(object):
def list(self, request):
queryset = self.get_queryset() # 继承后获取 模型对象(book对象集合。。)
ser_obj = self.get_serializer(queryset, many=True)
return Response(ser_obj.data) # post提交类
class CreateModelMixin(object):
def create(self, request):
ser_obj = self.get_serializer(data=request.data)
if ser_obj.is_valid(): # 如果检验成功
ser_obj.save() # 要调用create方法 需要去serializer中去写
return Response(ser_obj.validated_data) # 返回一个 ser_obj.validated_data 检验通过的数据 return Response(ser_obj.errors) # 没验证成功 就返回 ser_obj.errors 错误信息 # 检索类(查看单个对象的类)
class RetrieveModelMixin(object):
def retrieve(self, request, id):
book_obj = self.get_queryset().filter(id=id).first()
ser_obj = BookSerializer(book_obj)
return Response(ser_obj.data) # 更新类(局部更新)
class UpdateModelMixin(object):
def update(self, request, id):
book_obj = self.get_queryset().filter(id=id).first()
ser_obj = self.get_serializer(instance=book_obj, data=request.data, partial=True)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.validated_data)
return Response(ser_obj.errors) # 删除类
class DestroyModelMixin(object):
def destroy(self, request, id):
book_obj = self.get_queryset().filter(id=id).first()
if not book_obj:
return Response("您删除的书籍不存在")
book_obj.delete() # 记着删除操作
return Response("") # 所有的book
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin): # 继承通用类
queryset = Book.objects.all()
Serializer_class = BookSerializer def get(self, request):
return self.list(request) def post(self, request):
return self.create(request) # 单条book信息
class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
queryset = Book.objects.all()
Serializer_class = BookSerializer def get(self, request, id):
return self.retrieve(request, id) def put(self, request, id):
return self.update(request, id) def delete(self, request, id):
return self.destroy(request, id)

第一次封装views视图

我们封装的GenericAPIView,包括封装每个方法的类,其实框架都帮我们封装好了~~

我们可以直接继承这些类~~来实现上面的视图~~可是还有没有更简单的方法呢~我们再次封装一下~~

# 上面我们写的继承类太长了~~我们再改改(*args, ***kwargs),为了传参更安全一点

class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
pass class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
pass class BookView(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer 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 BookEditView(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer def get(self, request, id, *args, **kwargs):
return self.retrieve(request, id, *args, **kwargs) def patch(self, request, id, *args, **kwargs):
return self.update(request, id, *args, **kwargs) def delete(self, request, id, *args, **kwargs):
return self.delete(request, id, *args, **kwargs)

第二次封装

这次我们只是让继承变的简单了一点而已,好像并没有什么大的进步

小插曲

想想可不可以路由把这些参数都传过去呢,看看源码

点进as_view中查看

有接收参数的位置,但是在自己类中只做了个赋值,然后传参到父类中了

在父类中很友好的报错了。。

我们可不可以把这两个视图合并成一个视图呢~~~框架给我们提供了一个路由传参的方法~~

我们看下ViewSetMixin

多接受了一个参数

不传参还不报错。。

最后执行完后返回一个 豁免的 view  点进view中查看

在这里 他把路由参数 修改进源码属性了

在django 执行分发时候找到对应的方法

此时可知actions这个默认参数其实就是我们路由可以进行传参了~~~

我们要传的参数是一个字段~key应该是我们的请求方式,value应该对应我们处理的方法~

这样我们每个视图就不用在写函数了~因为已经和内部实现的函数相对应了~

第三次封装

from django.conf.urls import url
from .views import BookView, BookEditView, BookModelView # 第三次 路由 封装
urlpatterns = [
# url(r'^book$', BookView.as_view()),
# url(r'^book/(?P<id>\d+)', BookEditView.as_view()),
url(r'^book$', BookModelView.as_view({"get": "list", "post": "create"})),
url(r'^book/(?P<pk>\d+)', BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]

第三次路由封装

from rest_framework.viewsets import ViewSetMixin

# class BookView(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
# queryset = Book.objects.all()
# serializer_class = BookSerializer # 如果我们再定义一个类
class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
pass class BookModelView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer

第三次视图

我们现在的视图就只要写两行就可以了~~~

其实我们写的所有的视图~框架都帮我们封装好了~

注意一点~~用框架封装的视图~我们url上的那个关键字参数要用pk~~系统默认的~~

奉献一张图来看下我们的继承顺序~~~

DRF的路由

我们上面的路由传参写的特别多~~框架也帮我们封装好了~

# 路由封装
from .views import BookModelView
from rest_framework.routers import DefaultRouter # 帮助我们生成带参数的路由 router = DefaultRouter() # 实例化DefaultRouter对象
router.register(r'^book', BookModelView) # 注册我们的路由以及视图
urlpatterns =[]
urlpatterns += router.urls

路由

我们可以看到~~通过框架我们可以把路由视图都变的非常简单~~

但是需要自定制的时候还是需要我们自己用APIView写~~当不需要那么多路由的时候~也不要用这种路由注册~~

总之~~一切按照业务需要去用~~~

DRF的视图的更多相关文章

  1. DRF的视图和路由

    DRF的视图 APIView Django中写CBV的时候继承的是View,rest_framework继承的是APIView, urlpatterns = [ url(r'^book$', Book ...

  2. APIView (DRF的视图)

    APIView和View的区别 -- APIView继承了View -- APIView 重写了as_view以及 dispatch方法 -- 在dispatch里重新封装了request  -- r ...

  3. DRF 的视图,路由和渲染器

    DRF 的视图,路由和渲染器 1 视图 简单的增删改查 : ModelViewSet; 复杂的操作使用APIView 和 GenericViewSet APIView(View) class Home ...

  4. DRF的视图组件

    目录 DRF的视图组件 两大视图类 六大视图工具类 九大工具视图类 两大视图集基类 DRF的视图组件 DRF的视图组件大概分以下几类 两大视图类 APIView.GenericAPIView from ...

  5. DRF之视图类(mixin)源码解析

     同样的增删改查操作,如果我们还像之前序列化组件那样做,代码重复率过多,所以我们用视图表示: 具体源码实现:首先定义一个视图类,然后根据mixin点进去有五个封装好的方法,这五个方法共有的属性就是都需 ...

  6. DRF之视图和router

    1. 视图 Django REST framwork 提供的视图的主要作用: 控制序列化器的执行(检验.保存.转换数据) 控制数据库查询的执行 1.1. 请求与响应 1.1.1 Request RES ...

  7. drf之视图案例

    views.py from django.shortcuts import render # Create your views here. from rest_framework.generics ...

  8. DRF之视图组件

    不断的优化我们写的程序,是每个程序员必备的技能和职业素养,也是帮助我们成长的非常重要的手段. 使用serializer进行put接口设计 根据规范,PUT接口用来定义用户对数据修改的逻辑,也就是upd ...

  9. Django RestFramework(DRF)类视图

    基础视图 1.基础函数视图(@api_view) DRF提供了一种函数基础视图来装饰Django的普通视图,我们可以使用request来接受请求和response响应.一个小例子: from rest ...

随机推荐

  1. lightoj 1282 取对数的操作

    /* 前三位 len=log10n^k(乘积的长度) len=klog10n n^k=x*10^(len-1) x=n^k/10^(len-1) log10x = k*log10n - (len-1) ...

  2. IP的计算

    IP的计算 时间限制: 1 Sec  内存限制: 32 MB 位无符号整数来表示,一般用点分方式来显示,点将IP地址分成4个部分,每个部分为8位,表示成一个无符号整数(因此不需要用正号出现),如192 ...

  3. Fiddler抓包6-get请求(url详解)

    前言 上一篇介绍了Composer的功能,可以模拟get和post请求,get请求有些是不带参数的,这种比较容易,直接放到url地址栏就行.有些get请求会带有参数,本篇详细介绍url地址格式. 一. ...

  4. CentOS6.8安装MySQL5.7.20时报Curses library not found解决

    报错如下: CMakeErroratcmake/readline.cmake:83(MESSAGE): Curseslibrarynotfound.Pleaseinstallappropriatepa ...

  5. C++11新特性--decltype (转)

    返回值 decltype(表达式) [返回值的类型是表达式参数的类型] 这个可也用来决定表达式的类型,就像Bjarne暗示的一样,如果我们需要去初始化某种类型的变量,auto是最简单的选择,但是如果我 ...

  6. 饮冰三年-人工智能-linux-09 服务

    1:SSH服务(提供远程连接服务) 客户端使用Xshell 链接成功 加快连接速度 关闭防火墙 2:apache 服务(提供网页服务) 2.0 准备环境 关闭防火墙:service iptables ...

  7. Ajax爬虫必用到的字典转换器

    1.使用情景 在我们Ajax爬虫时需要用到以下这样的数据的时候我们会一个一个地复制粘贴,这样会很麻烦 def dictionary_converter(key_value): '''主要用于爬虫时复制 ...

  8. CAS统一登录认证好文汇集贴

    悟空的专栏 https://blog.csdn.net/u010475041/article/category/7156505 LinBSoft的专栏 https://blog.csdn.net/ol ...

  9. 【UOJ 209】【UER #6】票数统计

    题解: jls的题目还是比较好的 首先比较显然我们可以分析出 当x<y时,显然只能满足前缀条件 针对这一档部分分,是个简单的组合数 考虑一下后缀限制,发现真的不好搞.. 看了题解发现,枚举总共的 ...

  10. 用ArcMap打开MXD文件报One or more layers failed to draw错误!

    错误信息: One or more layers failed to draw: FDO error: 0General function failure [PW_X]参数不足,期待是 1. 原因: ...