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写~~当不需要那么多路由的时候~也不要用这种路由注册~~

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

最新文章

  1. [Android]依赖注入框架google的dagger
  2. cocos2d-x test学习[1]
  3. Arduino101学习笔记(八)&mdash;&mdash; 函数库
  4. 每日一SQL-善用DATEADD和DATEDIFF
  5. Easy Problem-map和vector的使用
  6. 排序 归并排序&amp;逆序对
  7. C# ADO.NET参数查询
  8. BZOJ 1064 假面舞会
  9. .net机试题总结
  10. Spring 配置文件XML -- &lt;beans&gt;中属性概述
  11. spring boot https --restful接口篇
  12. Servlet--ServletRequest接口,ServletResponse接口
  13. GitHub界面初识
  14. java中的 java.util.concurrent.locks.ReentrantLock类中的lockInterruptibly()方法介绍
  15. Elasticsearch System Call Filters Failed to Install
  16. VUE开发SPA之微信授权登录
  17. 剑指offer:矩形覆盖
  18. HBase实验(CRUD和MR入库)
  19. HDU 6214 Smallest Minimum Cut (最小割且边数最少)
  20. 温故而知新 forEach 无法中断(break)的问题

热门文章

  1. ubantu php7.0版本降级到php5.6
  2. DBCC CheckDB遇到a database snapshot could not be created
  3. break,continue的使用
  4. 用SQL语句添加删除修改字段_常用SQL
  5. 【poj1112】 Team Them Up!
  6. C语言 稀疏矩阵 压缩 实现
  7. 新建一个Activity
  8. Web前端开发Chrome插件
  9. html中表格table的内容居中显示
  10. Spring读取配置文件
  11. python basic programs
  12. j2ee基础
  13. VS 对于LINK fatal Error 问题 解决方案
  14. HTTP文件下载JAVA后台的实现
  15. golang:高性能消息队列moonmq的简单使用
  16. shell 批量远程主机执行命令
  17. 学号 20175201张驰 《Java程序设计》第8周学习总结
  18. shell脚本编写某一文件夹内拷贝某一段文件(有则跳过没有则拷贝)
  19. RuntimeError: cryptography requires setuptools 18.5 or newer, please upgrade to a newer version of setuptool
  20. Oracle课程档案,第七天