DRF 视图
目录
- 一.DRF中的Request
- 二.前戏: 关于面向对象的继承
- 三.初级版本
- 四.进化版: 使用自定义混合类和自定义通用类
- 五.超级进化版: 使用
GenericViewSet
通用类 - 六.究极进化版: 使用
rest_framework
帮我们封装好的通用类和混合类 - 七.终极进化版: 使用
rest_framework
帮我们封装好的路由DefaultRouter
一.DRF中的Request
在Django REST Framework中内置的Request类扩展了Django中的Request类, 实现了很多方便的功能 -- 如请求数据解析和认证等.
比如, 区别于Django中的request: 从request.GET
中获取URL参数, 从request.POST
中去取某些情况下的POST数据(前端提交过来的数据).
在APIView中封装的request, 就实现了请求数据的解析:
- 对于GET请求的参数, APIView通过
request.query_params
来获取 - 对于POST请求、PUT请求的数据, APIView通过
request.data
来获取
二.前戏: 关于面向对象的继承
# 讲一个葫芦娃的故事
class Wa1(object):
name = "红娃"
def f1(self):
print("力大无穷!")
class Wa2(object):
name = '橙娃'
def f2(self):
print('千里眼顺风耳!')
class Wa3(object):
name = '黄娃'
def f3(self):
print('钢筋铁骨!')
class Wa4(object):
name = '绿娃'
def f4(self):
print("会喷火!")
class Wa5(object):
name = '青蛙'
def f5(self):
print("会喷水!")
class Jishuwa(Wa1, Wa3, Wa5):
name = '奇数娃'
def ff(self):
print("我是{}, 我会:".format(self.name))
self.f1()
self.f3()
self.f5()
class Oushuwa(Wa2, Wa4):
name = '偶数娃'
def ff(self):
print("我是{}, 我会:".format(self.name))
self.f2()
self.f4()
jsw = Jishuwa()
jsw.ff()
osw = Oushuwa()
osw.ff()
# 直接定义一个基数娃
class Taowa(Wa1, Wa3, Wa5):
name = '套娃'
def ff(self):
print("我是{}, 我会:".format(self.name))
self.f1()
self.f3()
self.f5()
class Wawa(Taowa):
pass
print("=" * 120)
a = Wawa()
a.ff()
三.初级版本
1. settings.py
文件 -- 注册app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'bms.apps.BmsConfig',
'rest_framework', # 注册app
]
2. models.py
文件 -- 创建表
from django.db import models
# 出版社表
class Publisher(models.Model):
name = models.CharField(max_length=32)
def __str__(self):
return self.name
# 书籍表
class Book(models.Model):
title = models.CharField(max_length=32)
publisher = models.ForeignKey(to='Publisher', to_field='id', on_delete=models.CASCADE)
def __str__(self):
return self.title
# cd到当前项目目录
# 执行数据库迁移指令
python manage.py makemigrations
python manage.py migrate
3. admin.py
文件
from django.contrib import admin
from bms import models # bms是我们的app
admin.site.register(models.Publisher)
admin.site.register(models.Book)
# 创建超级用户
# cd到当前项目目录
python manage.py createsuperuser
# 启动Django项目
python manage.py runserver 127.0.0.1:8000
# 浏览器地址栏输入 127.0.0.1:8000
# 输入账号和密码,进入admin页面,对数据库中的表 添加或修改相关数据
4. 根目录下urls.py
-- 路由匹配
from django.conf.urls import url
from django.contrib import admin
from bms import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^book/$', views.BookListView.as_view()),
url(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view()),
]
5. bms/views.py
-- 视图函数
from rest_framework.response import Response
from rest_framework.views import APIView
from bms import models
from bms.modelserializers import BookModelSerializer
class BookListView(APIView):
def get(self, request):
# 1.从数据库查询出所有书籍对象
queryset = models.Book.objects.all()
# 2.使用modelserializer对获取的对象进行序列化
ser_obj = BookModelSerializer(queryset, many=True)
return Response(ser_obj.data)
def post(self, request):
# 1.获取前端提交过来的数据 --> request.data
# 2.对数据进行有效性校验
ser_obj = BookModelSerializer(data=request.data)
if ser_obj.is_valid():
ser_obj.save()
return Response('添加成功!')
else:
return Response(ser_obj.errors)
class BookDetailView(APIView):
def get(self, request, pk): # get获取具体某本书的信息
# 1.根据pk去数据库中查询具体的那本书籍对象
book_obj = models.Book.objects.filter(pk=pk).first()
if book_obj:
# 2.将书籍对象 序列化成 json格式的数据
ser_obj = BookModelSerializer(book_obj)
# 3.返回响应
return Response(ser_obj.data)
else:
return Response('无效的书籍id')
def put(self, request, pk): # put修改具体某本书的信息
# 1.根据pk去查询具体的那本书籍对象
book_obj = models.Book.objects.filter(pk=pk).first()
if book_obj:
# 2.获取用户发送过来的数据并修改数据
ser_obj = BookModelSerializer(instance=book_obj, data=request.data, partial=True)
if ser_obj.is_valid():
# 3.保存并返回修改后的数据
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
else:
return Response('无效的书籍id')
def delete(self, request, pk): # delete删除具体某一本书籍对象
# 1.根据pk去查询具体的那本书籍对象
book_obj = models.Book.objects.filter(pk=pk).first()
if book_obj:
# 2.删除该书籍对象
book_obj.delete()
return Response('删除成功')
else:
return Response('无效的书籍id')
6. bms/modelserializers.py
-- 自定义序列化工具
from rest_framework import serializers
from bms import models
class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField()
class BookModelSerializer(serializers.ModelSerializer):
publisher_info = serializers.SerializerMethodField(read_only=True)
def get_publisher_info(self, book_obj):
return PublisherSerializer(book_obj.publisher).data
class Meta:
model = models.Book
fields = '__all__'
extra_kwargs = {
'publisher': {'write_only': True},
}
class PublisherModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Publisher
fields = '__all__'
四.进化版: 使用自定义混合类和自定义通用类
提取出views.py
文件中函数BookListView
和BookDetailView
代码中的重复部分, 并将这些重复部分封装为通用类(Generic)和混合类(Mixin), 利用Python强大的多继承功能, 将代码进一步优化. 充分体现Python语言的"优雅"和"简洁".
注意: 混合类Mixin不能单独实例化, 需要与其他的类搭配使用.
bms/views.py
:
from rest_framework.response import Response
from rest_framework.views import APIView
from bms import models
from bms.modelserializers import BookModelSerializer, PublisherModelSerializer
# 通用功能
class GenericView(APIView):
queryset = None
serializer_class = None
def get_queryset(self, request, *args, **kwargs):
# 再一次调用all()方法: 让每次请求来的时候都重新查一次数据
return self.queryset.all()
def get_obj(self, request, pk, *args, **kwargs):
return self.get_queryset(request, *args, **kwargs).filter(pk=pk).first()
# get展示(全部)资源
class ListMixin(object):
def get(self, request):
queryset = self.get_queryset(request)
ser_obj = self.serializer_class(queryset, many=True)
return Response(ser_obj.data)
# post添加资源
class CreateMixin(object):
def post(self, request):
ser_obj = self.serializer_class(data=request.data)
if ser_obj.is_valid():
ser_obj.save()
return Response('添加成功!')
else:
return Response(ser_obj.errors)
# get展示(部分)资源
class RetrieveMixin(object):
def get(self, request, pk, *args, **kwargs):
obj = self.get_obj(request, pk, *args, **kwargs)
if obj:
ser_obj = self.serializer_class(obj)
return Response(ser_obj.data)
else:
return Response('无效的id!')
# put更新(修改)资源
class UpdateMixin(object):
def put(self, request, pk, *args, **kwargs):
obj = self.get_obj(request, pk, *args, **kwargs)
if obj:
ser_obj = self.serializer_class(instance=obj, data=request.data, partial=True)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
else:
return Response('无效的id!')
# delete删除资源
class DestroyMixin(object):
def delete(self, request, pk, *args, **kwargs):
obj = self.get_obj(request, pk, *args, **kwargs)
if obj:
obj.delete()
return Response('删除成功!')
else:
return Response('无效的id!')
class BookListView(GenericView, ListMixin, CreateMixin):
queryset = models.Book.objects.all()
serializer_class = BookModelSerializer
class BookDetailView(GenericView, RetrieveMixin, UpdateMixin, DestroyMixin):
queryset = models.Book.objects.all()
serializer_class = BookModelSerializer
class PublisherListView(GenericView, ListMixin, CreateMixin):
queryset = models.Publisher.objects.all()
serializer_class = PublisherModelSerializer
class PublisherDetailView(GenericView, RetrieveMixin, UpdateMixin, DestroyMixin):
queryset = models.Publisher.objects.all()
serializer_class = PublisherModelSerializer
urls.py
:
from django.conf.urls import url
from django.contrib import admin
from bms import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^book/$', views.BookListView.as_view()),
url(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view()),
url(r'^publisher/$', views.PublisherListView.as_view()),
url(r'^publisher/(?P<pk>\d+)$', views.PublisherDetailView.as_view()),
]
五.超级进化版: 使用GenericViewSet
通用类
GenericViewSet
是rest_framework
这个app中已经封装好了的一个类:
from rest_framework.viewsets import GenericViewSet
需要注意的是, 继承了GenericViewSet
以后, GenericViewSet
这个类已经帮我们封装好了get_queryset()
和get_object()
这两个方法, 它们不需要接收参数, 我们直接调用即可.
bms/views.py
:
from rest_framework.response import Response
from bms import models
from bms.modelserializers import BookModelSerializer, PublisherModelSerializer
from rest_framework.viewsets import GenericViewSet # 引入GenericViewSet通用类
# get展示(全部)资源
class ListMixin(object):
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
ser_obj = self.serializer_class(queryset, many=True)
return Response(ser_obj.data)
# post添加资源
class CreateMixin(object):
def create(self, request, *args, **kwargs):
ser_obj = self.serializer_class(data=request.data)
if ser_obj.is_valid():
ser_obj.save()
return Response('添加成功!')
else:
return Response(ser_obj.errors)
# get展示(部分)资源
class RetrieveMixin(object):
def retrieve(self, request, pk, *args, **kwargs):
obj = self.get_object()
if obj:
ser_obj = self.serializer_class(obj)
return Response(ser_obj.data)
else:
return Response('无效的id!')
# put更新(修改)资源
class UpdateMixin(object):
def update(self, request, pk, *args, **kwargs):
obj = self.get_object()
if obj:
ser_obj = self.serializer_class(instance=obj, data=request.data, partial=True)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
else:
return Response('无效的id!')
# delete删除资源
class DestroyMixin(object):
def destroy(self, request, pk, *args, **kwargs):
obj = self.get_object()
if obj:
obj.delete()
return Response('删除成功!')
else:
return Response('无效的id!')
class BookViewSet(GenericViewSet, ListMixin, CreateMixin, RetrieveMixin, UpdateMixin, DestroyMixin):
queryset = models.Book.objects.all()
serializer_class = BookModelSerializer
class PublisherViewSet(GenericViewSet, ListMixin, CreateMixin, RetrieveMixin, UpdateMixin, DestroyMixin):
queryset = models.Publisher.objects.all()
serializer_class = PublisherModelSerializer
urls.py
:
from django.conf.urls import url
from django.contrib import admin
from bms import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^book/$', views.BookViewSet.as_view(actions={'get': 'list', 'post': 'create'})),
url(r'^book/(?P<pk>\d+)$', views.BookViewSet.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
url(r'^publisher/$', views.PublisherViewSet.as_view(actions={'get': 'list', 'post': 'create'})),
url(r'^publisher/(?P<pk>\d+)$', views.PublisherViewSet.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
]
六.究极进化版: 使用rest_framework
帮我们封装好的通用类和混合类
bms/views.py
:
from bms import models
from bms.modelserializers import BookModelSerializer, PublisherModelSerializer
from rest_framework.viewsets import ModelViewSet
class BookViewSet(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = BookModelSerializer
class PublisherViewSet(ModelViewSet):
queryset = models.Publisher.objects.all()
serializer_class = PublisherModelSerializer
七.终极进化版: 使用rest_framework
帮我们封装好的路由DefaultRouter
from rest_framework.routers import DefaultRouter
from bms import views
urlpatterns = []
router = DefaultRouter()
router.register('book', views.BookViewSet)
router.register('publisher', views.PublisherViewSet)
# 重写urlpatterns
urlpatterns += router.urls
DRF 视图的更多相关文章
- 使用DRF视图集时自定义action方法
在我们用DRF视图集完成了查找全部部门,创建一个新的部门,查找一个部门,修改一个部门,删除一个部门的功能后,views.py的代码是这样子的: class DepartmentViewSet(Mode ...
- 【DRF视图】
目录 开始使用内置视图 请结合[DRF序列化]此文献中的数据文件及序列化文件来阅读如下代码. DRF视图为我们提供了非常简便的方法--内置了增删改查等一系列的操作. 我们只需在url中指定对应的方法, ...
- DRF视图-请求与响应
DRF视图 drf的代码简写除了在数据序列化体现以外,在视图中也是可以的.它在django原有的django.views.View类基础上,drf内部封装了许多子类以便我们使用. Django RES ...
- DRF视图组件
DRF视图组件: CVB模式继承----五层 from django.views import View # Django的View from rest_framework.views import ...
- drf 视图使用及源码分析
前言 drf视图的源码非常的绕,但是实现的功能却非常的神奇. 它能够帮你快速的解决ORM增删改查的重复代码,非常的方便好用. 下面是它源码中的一句话: class ViewSetMixin: &quo ...
- DRF 视图组件
目录 DRF 视图组件 视图组件大纲 两个视图基本类 五个扩展类 九个子类视图 视图集 常用视图集父类 魔法类 一览表 DRF中视图的"七十二变" 第一层:基于APIview的五个 ...
- restfull规范、DRF视图和路由
一.restfull规范的简单介绍 1.介绍 REST:表述性状态转移,是一种web交互方案 资源:在web中只要有被引用的必要都是资源 URI: URI 统一资源标识符 URL 统一资源定位符 统一 ...
- drf视图组件、认证组件
视图组件 1.基本视图 url(r'^publish/$', views.PublishView.as_view()), url(r'^publish/(?P<pk>\d+)/$', vi ...
- DRF 视图和路由
Django Rest Feamework 视图和路由 DRF的视图 APIView 我们django中写CBV的时候继承的是View,rest_framework继承的是APIView,那么他们两个 ...
- DRF 视图组件,路由组件
视图组件 -- 第一次封装 -- GenericAPIView(APIView): queryset = None serializer_class = None def ge ...
随机推荐
- 插入2D点,在WPF中使用Bezier曲线
原文Interpolate 2D points, usign Bezier curves in WPF Interpolate 2D points, usign Bezier curves in WP ...
- 汇编实现获取CPU信息
这是文章最后一次更新,加入了TLB与Cache信息等资料前言:论坛上面有人不明白CPUID指令的用法,于是就萌生写这篇文章的想法,若有错误话请大侠指出,谢谢了 ^^论坛的式样貌似有问题,若式样问题导致 ...
- .NET与 java通用的3DES加密解密方法
C#代码 private void button1_Click(object sender, EventArgs e) { string jiami = textBox1.Text; textBox2 ...
- epplus输出成thml
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- Java 线程池(一):开篇及Executor整体框架介绍
一.开篇 线程池.数据库连接池,在平时的学习中总能接触到这两个词,但它们到底是什么?和线程,数据库连接有什么关系?为什么需要“池”?“池”的概念及作用是什么?要弄清楚这些问题,就要深入到“池”的实现中 ...
- mysql启动脚本
一台服务器上安装多个MySQL实例之后,实例的启动关闭不能再用service mysqld start/stop/restart命令,所以编写如下脚本用于启动关闭对应端口的实例. 这个脚本适用于多实例 ...
- Android多线程(一)
在Android应用的开发过程中,我们不可避免的要使用多线程,获取服务器数据.下载网络数据.遍历文件目录查找特定文件等等耗时的工作都离不开线程的知识.Android继承了Java的多线程体系,同时又实 ...
- 在asp.net 中web.config配置错误页
每当用户访问错误页面时,会出现不友好的错误页面,所以为了防止这种不友好,我们在web.config中的<system.web>节点下配置 <customErrors>,在出现比 ...
- 进程间通信 - 动态链接库中共享内存(利用DLL的2~3G的地址段空间)
前言 进程是装入内存并准备执行的程序,每个进程都有私有的虚拟地址空间,由代码.数据,以及其他的一些资源组成.32位系统的进程分配4G的虚拟地址空间.内存地址范围是0x00000000-0xFFFFFF ...
- Bokeh 0.9.0dev 发布,交互式可视化库
快速使用Romanysoft LAB的技术实现 HTML 开发Mac OS App,并销售到苹果应用商店中. <HTML开发Mac OS App 视频教程> 土豆网同步更新:http: ...