drf 视图家族

前期准备

总路由 urls.py

from django.contib import admin
from django.views import serve
from django.conf import settings urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include('api.urls')),
url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
]

基表:utils/models.py

from django.db import models

class BaseModel(models.Model):
is_delete = models.BooleanField(default=False)
create_time = models.DateTimeField(auto_now_add=True, null=True) class Meta:
# 抽象表, 不会完成数据库迁移
abstract = True

模型层 api/models.py

from django.db import models
from utils.models import BaseModel class Book(BaseModel):
name = models.CharField(max_length=64)
price = models.DecimalField(max_digits=6, decimal_places=2)
img = models.ImageField(upload_to='icon', default='icon/default.png')
publish = models.ForeignKey(to='Publish',
null=True,
related_name='books',
db_constraint=False,
on_delete=models.DO_NOTHING
)
authors = models.ManyToManyField(to='Author',
related_name='authors',
db_constraint=False @property
def publish_info(self):
return {'name': self.publish.name, 'address': self.publish.address} @property
def author_info(self):
author_list = [] for author in self.authors.all():
detail = AuthorDetail.objects.filter(author_id=self.author.id)
author_list.append({
'name': author.name,
'age': author.age,
'mobile': '未知' if not detail else author.detail.mobile
}) return author_list class Meta:
db_table = "books"
verbose_name = '书籍'
verbose_name_plural = verbose_name def __str__(self):
return self.name class Author(BaseModel):
name = models.CharField(max_length=64)
age = models.IntegerField() @property
def mobile(self):
return self.detail.mobile class Meta:
db_table = 'author'
verbose_name = '作者'
verbose_name_plural = verbose_name def __str__(self):
return self.name class AuthorDetail(BaseModel):
mobile = models.CharField(max_length=11)
author = models.OneToOneField(to='Author',
null=True,
related_name='detail',
db_constraint=False,
on_delete=models.CASCADE
)
class Meta:
db_table = 'detail'
verbose_name = '作者详情'
verbose_name_plural = verbose_name def __str__(self):
return f"{self.author.name}的详情" class Publish(BaseModel):
name = models.CharField(max_length=64)
address = models.CharField(max_length=128) class Meta:
db_table = 'publish'
verbose_name = '出版社'
verbose_name_plural = verbose_name def __str__(self):
return self.name

序列化器 api/serializers.py

from rest_framework import serializers
from . import models class BookListSerializer(serializers.ListSerializer):
def update(self, instance, validated_data):
for ind, obj in enumerate(instance):
for attr, value in validated_data[ind].items():
if hasattr(obj, attr):
set(obj, attr, value)
obj.save()
return instance class BookV2ModelSerializer(serializers.ModelSerializer):
re_name = serializers.CharField(
min_length=3,
required=True,
write_only=True, # 只参与反序列化
error_messages={
'min_length': '太短了',
'required': '不能为空'
}
) class Meta:
model = models.Book
fields = ('name', 're_name', 'price', 'img', 'publish', 'publish_info', 'authors', 'authors_info')
list_serializer_class = BookListSerializer
extra_kwargs = {
'name':{
'min_length': 3,
'error_messages': {
'min_length': '太短了',
'required': '不能为空'
}
},
# 有默认值的字段会默认required为False,在反序列化中如果不传值不会进行校验,但是如果传值就会进行校验
'publish':{
'required': True,
'write_only': True,
'error_messages':{
'required': '不能为空'
}
},
'authors':{
'required': True,
'write_only': True,
'error_messages':{
'required': '不能为空'
}
},
} # 自定义校验规则
# 局部钩子
def validate_name(self, value):
if 'sb' in value:
raise serializers.ValidationError('书名包含敏感词汇')
return value # 全局钩子
def validate(self, attr):
name = attr.get('name')
re_name = attr.get('re_name')
publish = attr.get('publish')
if name != re_name:
raise serializers.ValidationError(
{'re_name': '两次书名不一致'}
) # 通过逻辑控制联合唯一
if models.Book.objects.filter(name=name, publish=publish):
raise serializers.ValidationError(
{'book': '书籍已存在'}
)
return attr

基本视图(views)

主要就是通过视图类APIView,里面的逻辑都需要自己去实现,需要自己写接口

子路由 api/urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^books/$', views.BookAPIView.as_view()),
url(r'^books/(?P<pk>.*)/$', views.BookAPIView.as_view()),
]

视图层 api/views.py

from rest_framework import views
from . import models, serializers
from utils.response import APIResponse class BookAPIView(views.APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
# 单取
if pk:
book_obj = models.Book.objects.filter(is_delete=False, pk=pk).first()
if not pk:
return APIResponse(1, 'pk有误')
book_ser = serializers.BookV2ModelSerializer(book_obj)
return APIResponse(0, 'ok', results=book_ser.data) # 群取
book_obj_list = models.Book.objects.filter(is_delete=False).all()
if not book_obj_list:
return APIResponse(1, '没有数据')
book_ser = serializers.BookV2ModelSerializer(book_obj_list, many=True)
return APIResponse(0, 'ok', results=book_ser.data) # 增加
def post(self, request, *args, **kwargs):
# 把单增也转换为群增
request_data = request.data
if isinstance(request_data, dict):
data = [request_data, ]
elif isinstance(request, list):
data = request_data
else:
return APIView(1, '数据格式有误') book_ser = serializers.BookV2ModelSerializer(data=data, many=True)
if book_ser.is_valid():
book_obj_list = book_ser.save()
results = serializers.BookV2ModelSerializer(book_obj_list, many=True).data
return APIResponse(0, 'ok', results=results)
else:
return APIResponse(1, '添加失败', results=book_ser.errors)

视图工具类(mixins)

  1. RetrieveModelMixin:retrieve方法实现了获取一个对象
  2. ListModelMixin:list方法实现了获取多个对象
  3. CreateModelMixin:create方法实现了增加一个对象
  4. UpdateModelMixin:update方法实现了单整体更新,partial_udate实现了单局部更新
  5. DestroyModelMixin:destory方法实现了单独删除

一般结合generics工具视图使用

工具视图(generics)

GenericAPIView

GenericAPIView,是generics家族的基类,主要帮我们把qureysetserializer_class封装成了属性,提供了以下三种方法:

  • get_qureyset():获取多个对象
  • get_object():获取一个对象
  • get_serializer(*args, **kwargs):获取序列化后的对象

GenericAPIView的子类们

继承了mixins中多个功能类和GenericAPIView基类

类名 实现接口
CreateAPIView 单增(post)
ListAPIView 多取(get)
RetrieveAPIView 单取(get)
DestroyAPIView 单删(delete)
UpdateAPIView 单局部(patch)及整体(put)修改
ListCreateAPIView 多取(get)和多增(post)
RetrieveUpdateAPIView 单取(get),单局部(patch)及整体(put)修改
RetrieveDestroyAPIView 单取(get)和单删(delete)
RetrieveUpdateDestroyAPIView 单取(get),单局部(patch)及整体(put)修改和单删(delete)

子路由 api/urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
# generics
url(r'^v1/books/$', views.BookGenericAPIView.as_view()),
url(r'^v1/books/(?P<pk>.*)/$', views.BookGenericAPIView.as_view()), # mixins + generics
url(r'^v2/books/$', views.BookMixinsGenericAPIView.as_view()),
url(r'^v2/books/(?P<pk>.*)/$', views.BookMixinsGenericAPIView.as_view()), # 系统整合mixins、generics
url(r'^v3/books/$', views.BookRetrieveUpdateAPIView.as_view()),
url(r'^v3/books/(?P<pk>.*)/$', views.BookRetrieveUpdateAPIView.as_view()),
]

视图层 api/views.py

from rest_framework import generics, mixins
from . import models, serializers
from utils.response import APIResponse # v1 generics - 视图基类
class BookGenericAPIView(generics.GenericAPIView):
queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
serializer_class = serializers.BookModelSerializer def get(self, request, *args, **kwargs):
if 'pk' in kwargs:
book_obj = self.get_object()
book_ser = self.get_serializer(book_obj)
return APIResponse(0, 'ok', results=book_ser.data)
book_query = self.get_queryset()
book_ser = self.get_serializer(book_query, many=True)
return APIResponse(0, 'ok', results=book_ser.data) def post(self, request, *args, **kwargs):
book_ser = self.get_serializer(data=request.data)
book_ser.is_valid(raise_exception=True)
book_obj = book_ser.save()
return APIResponse(0, 'ok', results=self.get_serializer(book_obj).data) # v2 mixins工具集 + generics视图基类
class BookMixinsGenericAPIView(mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
serializer_class = serializers.BookModelSerializer
def get(self, request, *args, **kwargs):
if 'pk' in kwargs:
response = self.retrieve(request, *args, **kwargs)
else:
response = self.list(request, *args, **kwargs)
return APIResponse(0, 'ok', results=response.data) def post(self, request, *args, **kwargs):
response = self.create(request, *args, **kwargs)
return APIResponse(0, 'ok', results=response.data) # v3 视图基类子类 - 工具视图类
class BookRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
serializer_class = serializers.BookModelSerializer

视图集(viewsets)

ViewSetMixin:视图集工具,重写了as_view方法, 完成了请求方式到视图类中的方法的映射

例如:.as_view({'get': 'retrieve', 'delete': 'remove_obj'}), 表示当请求方式为get的时候,则会调用retrieve函数,当请求方式为delete的时候,则会调用remove_obj函数

GenericViewSet:与模型类有关的接口视图集 - 可以从mixins那继承功能,也可以自定义功能

ViewSet:与模型类无关或不是标准模型类接口 - 一般都是自定义功能

子路由 api/urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^v4/books/$', views.BookGenericViewSet.as_view({
'get': 'list',
'post': 'create'
})),
url(r'^v4/books/(?P<pk>.*)/$', views.BookGenericViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'remove_book'
})),
]

视图层 api/views.py

from rest_framework import mixins, viewsets
from . import models, serializers
from utils.response import APIResponse class BookGenericViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet):
queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
serializer_class = serializers.BookModelSerializer def remove_book(self, request, *args, **kwargs):
pk = kwargs.get('pk')
try:
book_obj = models.Book.objects.get(is_delete=False, pk=pk)
book_obj.is_delete = True
book_obj.save()
return APIResponse(0, '删除成功')
except:
return APIResponse(1, '删除失败')

drf--视图家族的更多相关文章

  1. DRF 视图家族及路由层补充

    目录 视图家族 一.views视图类 1.APIView类 2.GenericAPIView类(generics中) 二.mixins类:视图辅助工具 1.RetrieveModelMixin 2.L ...

  2. drf框架 - 视图家族 | GenericAPIView | mixins | generics | viewsets

    视图家族 view:视图 generics:工具视图 mixins:视图工具集 viewsets:视图集 学习曲线: APIView => GenericAPIView => mixins ...

  3. drf序列化组件之视图家族

    一.视图家族的分类 1.导入分类 from rest_framewok import views, generics, mixins, viewsets views:视图类 ​ 两大视图类:APIVi ...

  4. drf序列化高级、自定义只读只写、序列化覆盖字段、二次封装Response、数据库查询优化(断关联)、十大接口、视图家族

    目录 自定义只读 自定义只写 序列化覆盖字段 二次封装Response 数据库关系分析 断外键关联关系 ORM操作外键关系 ORM四种关联关系 基表 系列化类其他配置(了解) 十大接口 BaseSer ...

  5. drf二次封装response-APIViews视图家族-视图工具集-工具视图-路由组件

    视图类传递参数给序列化类 (1).在视图类中实例化 序列化对象时,可以设置context内容. (2).在序列化类中的局部钩子.全局钩子.create.update方法中,都可以用self.conte ...

  6. 视图家族 & 路由组件

    目录 视图家族 & 路由组件 视图集与路由组件 基于 GenericAPIView 的十大接口 基于 generics 包下工具视图类的六大基础接口 视图集 路由组件:必须配合视图集使用 自定 ...

  7. 使用DRF视图集时自定义action方法

    在我们用DRF视图集完成了查找全部部门,创建一个新的部门,查找一个部门,修改一个部门,删除一个部门的功能后,views.py的代码是这样子的: class DepartmentViewSet(Mode ...

  8. 【DRF视图】

    目录 开始使用内置视图 请结合[DRF序列化]此文献中的数据文件及序列化文件来阅读如下代码. DRF视图为我们提供了非常简便的方法--内置了增删改查等一系列的操作. 我们只需在url中指定对应的方法, ...

  9. day73_10_18视图家族与序列化的传参。

    一.序列化传参 在视图类中实例化序列对象时,还有一个参数为context,这个参数是存放字典,将所有从前端传来的数据传输到序列化中,比如需要在序列化中校验当前用户. 传入的request参数也是一个对 ...

  10. DRF视图-请求与响应

    DRF视图 drf的代码简写除了在数据序列化体现以外,在视图中也是可以的.它在django原有的django.views.View类基础上,drf内部封装了许多子类以便我们使用. Django RES ...

随机推荐

  1. PAT 乙级 1048.数字加密 C++/Java

    题目来源 本题要求实现一种数字加密方法.首先固定一个加密用正整数 A,对任一正整数 B,将其每 1 位数字与 A 的对应位置上的数字进行以下运算:对奇数位,对应位的数字相加后对 13 取余——这里用 ...

  2. 第11节-BLE协议HCI层的硬件接口

    本篇博客由韦东山视频整理所得 如何控制链路层让其发出广播包.数据包?通过HCI层向它发出命令,也可以通过ATT层.L2CAP层向LL层发出数据. 学习资料: 蓝牙协议core_v5.0.pdf < ...

  3. VIJOS-P1320 清点人数

    JDOJ 1427: VIJOS-P1320 清点人数 题目传送门 Description 初始时,火车上没有学生:当同学们开始上火车时,年级主任从第一节车厢出发走到最后一节车厢,每节车厢随时都有可能 ...

  4. 第二阶段冲刺(个人)——five

    今天的计划:优化登录.注册信息的填写判断. 昨天做了什么?做背景. 困难:无

  5. Java 字符流读写文件

    据说,java读写文件要写很多,贼麻烦,不像c艹,几行代码就搞定.只能抄抄模板拿来用了. 输入输出流分字节流和字符流.先看看字符流的操作,字节转化为字符也可读写. 一.写入文件 1.FileWrite ...

  6. thinkphp5.0 中简单处理微信支付异步通知

    public function wx_notify(){ $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; libxml_disable_ent ...

  7. Candy Treasure Box

    This is an interesting puzzle game. In the game, you need to use your brain, think carefully, operat ...

  8. Vue Echarts 饼图设置默认选中一个

    Vue Echarts 饼图设置默认选中一个 myChart.setOption(data) // data伟echarts所需要传入的参数,就是配置参数最多的那个玩意 myChart.dispatc ...

  9. JS的ES7支持

    1.指数运算符(幂): ** 2.Array.prototype.includes(value) : 判断数组中是否包含指定value console.log(2**4); let arr = [2, ...

  10. ABP abp zreo 老版本 支持dotnet framework 4.0

    下载了个abp zreo的老版本,module-zero-template-1.5.1, 只有这个版本支持.net framework4.0,其它都依赖.net framework 4.5和4.6去了 ...